【问题标题】:How to markup a transparent pygtk pycairo window and save the combined image?如何标记透明的 pygtk pycairo 窗口并保存组合图像?
【发布时间】:2012-04-29 01:01:17
【问题描述】:

我正在尝试开发一个透明窗口,我可以在该窗口上标记屏幕上的任何内容(包括动态)。 我的最终目标是在在线科学出版物中叠加图表,单击并沿曲线累积点 并最终使用生成器函数对收集的点进行曲线拟合。 这将包括放置线和轴、刻度线和其他好东西。 但是,我试图让问题代码保持非常简单。

下面的代码在透明度部分做得相当好(请批评和纠正)。 我进行了广泛的研究以了解如何保存透明窗口的内容,但失败了。 我试图弄清楚如何覆盖任何东西(绘制图元)但失败了。 我寻求任何和所有的建议来推动这个项目,并打算使最终的代码开源。

请帮忙。


    #!/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()

更新!得到了我需要工作的大部分东西,除了大的。 如何保存底层窗口和透明覆盖组合形成的图像? 可以使用 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()

【问题讨论】:

  • 回答了我自己的许多问题。只剩下最大的一个:
  • 嗨@jlettvin 这是一个好主意,我想试试你的代码。但是,您在上面发布的内容似乎与“十字准线”和“dn”功能有关:例如if 0 0))。此外,缺少“退出”等功能......您能更新上面的代码吗?

标签: python drawing transparency pygtk pycairo


【解决方案1】:

这并不能回答您的具体问题,但我想:为什么要重新发明轮子?我的建议是您使用像快门这样的高级屏幕截图应用程序来捕获窗口或选择。 Shutter 将为您提供“已保存”窗口的可浏览图库,并能够根据用户定义的配置文件进行编辑和网络发布,以及自动将图像存储在专用文件夹中(按项目、所需分辨率等)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 2014-03-13
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    相关资源
    最近更新 更多