2012-04-29 52 views
1

我想開發一個透明的窗口,我可以在其上標記任何在我的屏幕上(包括動態)的窗口。 我的最終目標是覆蓋在線科學出版物中的圖表,點擊並累積沿曲線 的點,並最終使用生成器函數來曲線擬合所收集的點。 這將包括放置線和軸,刻度線和其他好東西。 但是,我試圖保持問題代碼非常簡單。如何標記透明pygtk pycairo窗口並保存組合圖像?

下面的代碼很好地完成了透明度部分(請批評和糾正)。 我已經做了大量的研究,以瞭解如何保存透明窗口的內容,並失敗。 我試圖弄清楚如何覆蓋任何東西(繪圖原語)並失敗。 我尋求任何和所有建議,推動這個項目,並打算使最終的代碼開源。

請幫忙。


    #!/usr/bin/env python 
    """ 
    trans.py Transparent window with markup capability. 
    Goals: 
     1. make a transparent window that dynamically updates (working). 
     2. draw opaque points, lines, text, and more (unimplemented). 
     3. save window overlayed by opaque points to png (unimplemented). 
     4. toggle overlay on/off (unimplemented). 
     5. make cursor XOR of CROSSHAIR (unimplemented). 
    """ 

    import pygtk 
    pygtk.require('2.0') 
    import gtk, cairo 

    class Transparency(object): 
     def __init__(self, widget, index): 
      self.xy = widget.get_size() 
      self.cr = widget.window.cairo_create() 
      self.index = index 
     def __enter__(self): 
      self.cr.set_operator(cairo.OPERATOR_CLEAR) 
      self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *self.xy) 
      self.cr.rectangle(0.0, 0.0, *self.xy) 
      self.cr.fill() 
      return self.cr, self.surface 
     def __exit__(self, exc_type, exc_val, exc_tb): 
      filename = '%08d.png' % (self.index) 
      with open(filename, 'w+') as png: 
       self.surface.write_to_png(png) 
       print filename 
      self.cr.set_operator(cairo.OPERATOR_OVER) 

    class Expose(object): 
     def __init__(self): 
      self.index = 0 
     def __call__(self, widget, event): 
      with Transparency(widget, self.index) as (cr, surface): 
       # cr and surface are available for drawing. 
       pass 
      self.index += 1 

    def main(): 
     x, y = 201, 201 
     win = gtk.Window(gtk.WINDOW_TOPLEVEL) 
     win.connect("destroy", lambda w: gtk.main_quit()) 
     win.set_decorated(True) 
     win.set_app_paintable(True) 
     win.set_size_request(x, y) 
     win.set_colormap(win.get_screen().get_rgba_colormap()) 
     win.connect('expose-event', Expose()) 
     win.realize() 
     win.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.DIAMOND_CROSS)) 
     win.show() 
     gtk.main() 

    if __name__ == "__main__": 
     main() 

UPDATE!得到了大部分我需要的工作,除了BIG之外。 如何保存底層窗口和透明覆蓋圖組合形成的圖像? 積分可以放下,覆蓋可以使用vi風格的鍵盤控制來切換。 下面是最新的源:


    #!/usr/bin/env python 
    """ 
    trans.py Transparent window with markup capability. 
    Goals: 
     1. make a transparent window that dynamically updates (working). 
     2. draw opaque points, lines, text, and more (working). 
     3. save window overlayed by opaque points to png (unimplemented). 
     4. toggle overlay on/off (working). 
     5. make cursor XOR of CROSSHAIR (using pixel-wise crosshair instead). 
     6. enable keyboard input in original emacs function table style (working). 
    """ 

    import pygtk 
    pygtk.require('2.0') 
    import gtk, cairo 
    from math import pi 

    class Transparency(object): 
     index = 0 
     def __init__(self, widget): 
      self.xy = widget.get_size() 
      self.cr = widget.window.cairo_create() 
      self.storing = False 
     def __enter__(self): 
      self.cr.set_operator(cairo.OPERATOR_CLEAR) 
      self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *self.xy) 
      self.cr.rectangle(0.0, 0.0, *self.xy) 
      self.cr.fill() 
      return self.cr, self.surface 
     def __exit__(self, exc_type, exc_val, exc_tb): 
      if self.storing: 
       filename = '%08d.png' % (Transparency.index) 
       with open(filename, 'w+') as png: 
        self.surface.write_to_png(png) 
        print filename 
      self.cr.set_operator(cairo.OPERATOR_OVER) 
      Transparency.index += 1 

    class Expose(object): 
     def __init__(self, window, xy): 
      self.keep, self.points, self.bare = False, set(), False 
      self.window = window 
      self.X, self.Y = self.xy = xy 
      self.x1, self.y1 = self.x0, self.y0 = self.xy[0]/2, self.xy[1]/2 
      self.window.connect("key_press_event", self.key_press_event) 
      self.window.set_events(gtk.gdk.KEY_PRESS_MASK) 
      self.window.set_flags(gtk.HAS_FOCUS | gtk.CAN_FOCUS) 
      self.window.grab_focus() 
      # function table for keyboard driving 
      self.function = [[self.noop for a in range(9)] for b in range(256)] 
      self.function[ord('q')][0] = self.quit # q for quit 
      self.function[ord('h')][0] = self.lf # h for left (vi-style) 
      self.function[ord('j')][0] = self.dn # j for down (vi-style) 
      self.function[ord('k')][0] = self.up # k for up (vi-style) 
      self.function[ord('l')][0] = self.rt # l for right (vi-style) 
      self.function[ord('h')][2] = self.lf # h for left (vi-style) with point 
      self.function[ord('j')][2] = self.dn # j for down (vi-style) with point 
      self.function[ord('k')][2] = self.up # k for up (vi-style) with point 
      self.function[ord('l')][2] = self.rt # l for right (vi-style) with point 
      self.function[ord('.')][0] = self.mark # . for point 
      self.function[ord(',')][0] = self.state # , to toggle overlay 
     def __call__(self, widget, event): 
      self.xy = widget.get_size() 
      self.x0, self.y0 = self.xy[0]/2, self.xy[1]/2 
      with Transparency(widget) as (cr, surface): 
       if not self.bare: 
        self.point( cr, surface) 
        self.aperture(cr, surface) 
        self.positions(cr, surface) 
        self.crosshair(cr, surface) 
     def aperture(self, cr, surface): 
       cr.set_operator(cairo.OPERATOR_OVER) 
       cr.set_source_rgba(0.5,0.0,0.0,0.5) # dim red transparent 
       cr.arc(self.x0, self.y0, self.x0, 0, pi*2) 
       cr.fill() 
       return self 
     def position(self, cr, surface, x, y, chosen): 
      cr.set_operator(cairo.OPERATOR_OVER) 
      #r, g, b, a = (0.0,0.0,0.0,1.0) if chosen else (0.0,0.0,1.0,0.5) 
      r, g, b, a = (0.0,0.0,0.0,1.0) 
      cr.set_source_rgba(r,g,b,a) 
      cr.rectangle(x, y, 1, 1) 
      cr.fill() 
     def crosshair(self, cr, surface): 
      for dx, dy in [(-2,-2),(-1,-1),(1,1),(2,2),(-2,2),(-1,1),(1,-1),(2,-2)]: 
       x, y = self.x1 + dx, self.y1 + dy 
       if 0  0)) 
     def dn(self, c, n): self.newxy(0, +int(self.y1  0), 0) 
     def rt(self, c, n): self.newxy(+int(self.x1 127 else key 
     def key_press_event(self, widget, event): 
      keyname = gtk.gdk.keyval_name(event.keyval) 
      mask = (1*int(0 != (event.state&gtk.gdk. SHIFT_MASK))+ 
        2*int(0 != (event.state&gtk.gdk.CONTROL_MASK))+ 
        4*int(0 != (event.state&gtk.gdk. MOD1_MASK))) 
      self.keep = 0 != (mask & 2) 
      self.function[self.accept(event.keyval)][mask](keyname, event.keyval) 
      self(widget, event) 
      return True 

    def main(): 
     x, y = xy = [201, 201] 
     window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
     window.connect("destroy", gtk.main_quit) 
     window.set_decorated(True) 
     window.set_app_paintable(True) 
     window.set_size_request(x, y) 
     window.set_colormap(window.get_screen().get_rgba_colormap()) 
     window.connect('expose-event', Expose(window, xy)) 
     window.realize() 
     window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.DIAMOND_CROSS)) 
     window.show() 
     gtk.main() 

    if __name__ == "__main__": 
     main() 
+0

回答了很多我自己的問題。只有最大的一個仍然是: – jlettvin 2012-04-29 06:09:35

+0

hi @jlettvin這是一個好主意,我想嘗試一下你的代碼。然而,你上面發佈的內容似乎被'十字線'和'dn'功能所破壞:例如'if 0 0))'。此外,'退出'等功能缺失......請你更新上面的代碼? – venzen 2013-12-16 04:34:59

回答

0

這不回答你的具體問題,但我想:爲什麼要重新發明輪子?我的建議是,您使用快門等高級截圖應用程序來捕獲窗口或選擇。根據用戶定義的配置文件,Shutter將爲您提供一個可以瀏覽的「已保存」窗口畫廊,並具有編輯和網絡發佈功能,以及自動將圖像存儲在專用文件夾中(按項目,所需分辨率等)。