I am trying to develop a transparent window on which I can markup ANYTHING that is on my screen (including dynamic). My final goal is to overlay graphs in online scientific publications, click and accumulate points along curves and eventually use generator functions to curve-fit to the points gathered. This will include putting up lines and axes, tick marks, and other goodies. However, I am trying to keep the question code very simple.
The code below does the transparency part fairly well (please criticize and correct). I have done extensive research to understand how to save the contents of the transparent window, and failed. I have tried to figure out how to overlay anything at all (drawing primitives) and failed. I seek any and all advice to move this project forward, and intend to make the final code open source.
Please help.
#!/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! Got most of what I needed working except the BIG one. How do you save the image formed by the combination of the underlying window and the transparent overlay? Points can be layed down and overlay can be toggled using keyboard only controls in vi-style. Here is the latest source:
#!/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>k.gdk. SHIFT_MASK))+
2*int(0 != (event.state>k.gdk.CONTROL_MASK))+
4*int(0 != (event.state>k.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()
This does not answer your specific question but I figure: why re-invent the wheel? My suggestion is that you use an advanced screenshot application like Shutter to capture windows or selections. Shutter will provide you with a browseable gallery of your "saved" windows with the ability to edit and web-publish, as well as automatically storing images in dedicated folders (by project, desired resolution, etc) according to user defined profiles.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.