I wanted a quick way to find out which file contains certain python modules, this can by done by looking at __file__ variable for a module.
e.g. in the interpreter
>>> import pygame
>>> print pygame.__file__
/usr/lib64/python2.7/site-packages/pygame/__init__.pyc
Thursday, 19 September 2013
Wednesday, 18 September 2013
screenshots using Python under Linux
I have been working on porting some code to Linux and required a method to grab a screenshot of a window using python. I could just execute a command line application such as scrot, but I wanted to see if there was an easy way in native python.
Turns out it is fairly straight forward.
First I looked at taking a basic image of the whole screen, then tried to modify it to allow me to grab particular windows.
My first attempt seemed to work but the output image was skewed, this was using pygtk (gtk.gdk).
#!/usr/bin/python
'''
Modified from example at http://ubuntuforums.org/showthread.php?t=448160&p=2681009#post2681009
'''
import gtk.gdk
import os
import time
import Image
def screenGrab():
root_win = gtk.gdk.get_default_root_window()
size = root_win.get_size()
pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,size[0],size[1])
pixbuf = pixbuf.get_from_drawable(root_win,root_win.get_colormap(),0,0,0,0,size[0],size[1])
if (pixbuf == None):
return False
else:
width,height=size[0],size[1]
return Image.fromstring("RGB",(width,height),pixbuf.get_pixels())if __name__ == '__main__':
screen=screenGrab()
#screen.show()
screen.save(os.getcwd()+'/'+str(int(time.time()))+'.png', 'PNG')
This appeared to be using gtk2, was there anyway to use gtk3?
While searching I found a tutorial on PyCairo and this had an example of taking a screenshot using Gdk and using a cairo Image Surface. This seemed to do what I needed.
#!/usr/bin/python
'''
Modified from
ZetCode PyCairo tutorial
This code example takes a screenshot.
Original author: Jan Bodnar
website: zetcode.com
'''
from gi.repository import Gdk
import cairo
import os
import time
def main():
root_win = Gdk.get_default_root_window()
width = root_win.get_width()
height = root_win.get_height()
image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
pixbuf = Gdk.pixbuf_get_from_window(root_win, 0, 0, width, height)
cr = cairo.Context(image_surface)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
cr.paint()
image_surface.write_to_png("screenshot-"+str(int(time.time()))+".png")
if __name__ == "__main__":
main()
Now to modify this to capture a particular window. I can get information on any window using xwininfo, included in this is the xid (window id).
If I have the id of the window I want to capture can use the function GdkX11.X11Window.foreign_new_for_display() to switch to this window instead of the root window before creating the pixbuf and image surface.
#!/usr/bin/python
'''
Modified from
ZetCode PyCairo tutorial
original author: Jan Bodnar
website: zetcode.com
This code example takes a screenshot of particular window, id in hex
supplied as first argument
'''
from gi.repository import Gdk
from gi.repository import GdkX11
import cairo
import os
import time
import sys
def main():
winid = int(sys.argv[1],16)
root_win = GdkX11.X11Display.get_default()
win = GdkX11.X11Window.foreign_new_for_display(root_win,winid)
width = win.get_width()
height = win.get_height()
image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
pixbuf = Gdk.pixbuf_get_from_window(win, 0, 0, width, height)
cr = cairo.Context(image_surface)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
cr.paint()
image_surface.write_to_png("screenshot-"+str(int(time.time()))+".png")
if __name__ == "__main__":
main()
This works well, however I do not want to have to rely on an external application to get the id. Can I supply a window name and do the same thing?
GdkX11.X11Window.foreign_new_for_display() as well as taking a window id as an argument also takes a window object, so I just need to find a way to identify which window. This was not successful, however if I can identify the window by the name I can just pass the id of that window to GdkX11.X11Window.foreign_new_for_display().
This worked and now I have a script that will take a window name and dump an image of it to a png file.
#!/usr/bin/python
'''
Expanded upon code from
ZetCode PyCairo tutorial
original author: Jan Bodnar
website: zetcode.com
This code example takes a screenshot of a particular window from name
passed as argument.
'''
from gi.repository import Gdk
from gi.repository import GdkX11
import Xlib
import Xlib.display
import cairo
import os
import time
import sys
def get_window(name):
mydisplay = Xlib.display.Display()
root_win = mydisplay.screen().root
window_list = [root_win]
while len(window_list) != 0:
win = window_list.pop(0)
#print win.get_wm_name()
if win.get_wm_name() == name:
return win.id
children = win.query_tree().children
if children != None:
window_list += children
print 'Unable to find window matching - %s\n' % name
sys.exit(1)
return None
def main():
root_win = GdkX11.X11Display.get_default()
browser_win = get_window(sys.argv[1])
win = GdkX11.X11Window.foreign_new_for_display(root_win,browser_win)
width = win.get_width()
height = win.get_height()
image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
pixbuf = Gdk.pixbuf_get_from_window(win, 0, 0, width, height)
cr = cairo.Context(image_surface)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
cr.paint()
image_surface.write_to_png("screenshot-"+str(int(time.time()))+".png")
if __name__ == "__main__":
main()
Turns out it is fairly straight forward.
First I looked at taking a basic image of the whole screen, then tried to modify it to allow me to grab particular windows.
My first attempt seemed to work but the output image was skewed, this was using pygtk (gtk.gdk).
#!/usr/bin/python
'''
Modified from example at http://ubuntuforums.org/showthread.php?t=448160&p=2681009#post2681009
'''
import gtk.gdk
import os
import time
import Image
def screenGrab():
root_win = gtk.gdk.get_default_root_window()
size = root_win.get_size()
pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,size[0],size[1])
pixbuf = pixbuf.get_from_drawable(root_win,root_win.get_colormap(),0,0,0,0,size[0],size[1])
if (pixbuf == None):
return False
else:
width,height=size[0],size[1]
return Image.fromstring("RGB",(width,height),pixbuf.get_pixels())if __name__ == '__main__':
screen=screenGrab()
#screen.show()
screen.save(os.getcwd()+'/'+str(int(time.time()))+'.png', 'PNG')
This appeared to be using gtk2, was there anyway to use gtk3?
While searching I found a tutorial on PyCairo and this had an example of taking a screenshot using Gdk and using a cairo Image Surface. This seemed to do what I needed.
#!/usr/bin/python
'''
Modified from
ZetCode PyCairo tutorial
This code example takes a screenshot.
Original author: Jan Bodnar
website: zetcode.com
'''
from gi.repository import Gdk
import cairo
import os
import time
def main():
root_win = Gdk.get_default_root_window()
width = root_win.get_width()
height = root_win.get_height()
image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
pixbuf = Gdk.pixbuf_get_from_window(root_win, 0, 0, width, height)
cr = cairo.Context(image_surface)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
cr.paint()
image_surface.write_to_png("screenshot-"+str(int(time.time()))+".png")
if __name__ == "__main__":
main()
Now to modify this to capture a particular window. I can get information on any window using xwininfo, included in this is the xid (window id).
If I have the id of the window I want to capture can use the function GdkX11.X11Window.foreign_new_for_display() to switch to this window instead of the root window before creating the pixbuf and image surface.
#!/usr/bin/python
'''
Modified from
ZetCode PyCairo tutorial
original author: Jan Bodnar
website: zetcode.com
This code example takes a screenshot of particular window, id in hex
supplied as first argument
'''
from gi.repository import Gdk
from gi.repository import GdkX11
import cairo
import os
import time
import sys
def main():
winid = int(sys.argv[1],16)
root_win = GdkX11.X11Display.get_default()
win = GdkX11.X11Window.foreign_new_for_display(root_win,winid)
width = win.get_width()
height = win.get_height()
image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
pixbuf = Gdk.pixbuf_get_from_window(win, 0, 0, width, height)
cr = cairo.Context(image_surface)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
cr.paint()
image_surface.write_to_png("screenshot-"+str(int(time.time()))+".png")
if __name__ == "__main__":
main()
This works well, however I do not want to have to rely on an external application to get the id. Can I supply a window name and do the same thing?
GdkX11.X11Window.foreign_new_for_display() as well as taking a window id as an argument also takes a window object, so I just need to find a way to identify which window. This was not successful, however if I can identify the window by the name I can just pass the id of that window to GdkX11.X11Window.foreign_new_for_display().
This worked and now I have a script that will take a window name and dump an image of it to a png file.
#!/usr/bin/python
'''
Expanded upon code from
ZetCode PyCairo tutorial
original author: Jan Bodnar
website: zetcode.com
This code example takes a screenshot of a particular window from name
passed as argument.
'''
from gi.repository import Gdk
from gi.repository import GdkX11
import Xlib
import Xlib.display
import cairo
import os
import time
import sys
def get_window(name):
mydisplay = Xlib.display.Display()
root_win = mydisplay.screen().root
window_list = [root_win]
while len(window_list) != 0:
win = window_list.pop(0)
#print win.get_wm_name()
if win.get_wm_name() == name:
return win.id
children = win.query_tree().children
if children != None:
window_list += children
print 'Unable to find window matching - %s\n' % name
sys.exit(1)
return None
def main():
root_win = GdkX11.X11Display.get_default()
browser_win = get_window(sys.argv[1])
win = GdkX11.X11Window.foreign_new_for_display(root_win,browser_win)
width = win.get_width()
height = win.get_height()
image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
pixbuf = Gdk.pixbuf_get_from_window(win, 0, 0, width, height)
cr = cairo.Context(image_surface)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0)
cr.paint()
image_surface.write_to_png("screenshot-"+str(int(time.time()))+".png")
if __name__ == "__main__":
main()
Labels:
python,
screen capture,
screenshot,
scrot,
X
Wednesday, 11 September 2013
Moving mouse and pressing keys in X using python
I have just seen a cool piece of code in python which simulates key presses and mouse clicks to automatically play a browser based game. This was on Windows but it got me thinking of how similar keyboard and mouse events could be simulated in Linux using pure python (I could wrap programs such as xvkbd or xdotool, or even write some extensions in C and hook into xlib).
Fortunately someone has already written a python X library (Xlib) which I can utilise. Here are a couple of simple programs to get an idea of how to simulate mouse and keypress events.
First up how to move the mouse. This snippet moves the moves to a set location and clicks the first mouse button (left click for my setup)
#!/usr/bin/python
from Xlib import X, display, ext
d = display.Display()
s = d.screen()
root = s.root
#move pointer to set location
root.warp_pointer(300,300)
d.sync()
#press button 1, for middle mouse button use 2, for opposite button use 3
ext.xtest.fake_input(d, X.ButtonPress,1)
d.sync()
#we want a click so we need to also relese the same button
ext.xtest.fake_input(d, X.ButtonRelease,1)
d.sync()
Now, how to simulate keypresses.
#!/usr/bin/python
from Xlib import XK, display, ext, X
d=display.Display()
#send F1 as in gnome this will bring up help screen, proves it works
keysym=XK.string_to_keysym("F1")
keycode=d.keysym_to_keycode(keysym)
#press key
ext.xtest.fake_input(d, X.KeyPress, keycode)
d.sync()
#remember to release it, otherwise help screen will continue to appear
ext.xtest.fake_input(d, X.KeyRelease, keycode)
d.sync()
Fortunately someone has already written a python X library (Xlib) which I can utilise. Here are a couple of simple programs to get an idea of how to simulate mouse and keypress events.
First up how to move the mouse. This snippet moves the moves to a set location and clicks the first mouse button (left click for my setup)
#!/usr/bin/python
from Xlib import X, display, ext
d = display.Display()
s = d.screen()
root = s.root
#move pointer to set location
root.warp_pointer(300,300)
d.sync()
#press button 1, for middle mouse button use 2, for opposite button use 3
ext.xtest.fake_input(d, X.ButtonPress,1)
d.sync()
#we want a click so we need to also relese the same button
ext.xtest.fake_input(d, X.ButtonRelease,1)
d.sync()
Now, how to simulate keypresses.
#!/usr/bin/python
from Xlib import XK, display, ext, X
d=display.Display()
#send F1 as in gnome this will bring up help screen, proves it works
keysym=XK.string_to_keysym("F1")
keycode=d.keysym_to_keycode(keysym)
#press key
ext.xtest.fake_input(d, X.KeyPress, keycode)
d.sync()
#remember to release it, otherwise help screen will continue to appear
ext.xtest.fake_input(d, X.KeyRelease, keycode)
d.sync()
Tuesday, 10 September 2013
OpenIndiana
I have not used Solaris in some time so I thought it would be interesting to get OpenSolaris installed under kvm to test out. However, this has stopped being produced, but there is a fork called OpenIndiana.
I downloaded the Live dvd for desktops and booted that up under kvm, I have given the vm a qcow2 format disk to install to.
Once the OS boots up there is an option to install to disk, this will take you through a few install questions and then install to disk.
I downloaded the Live dvd for desktops and booted that up under kvm, I have given the vm a qcow2 format disk to install to.
Once the OS boots up there is an option to install to disk, this will take you through a few install questions and then install to disk.
Labels:
KVM,
OpenIndiana,
Solaris
Thursday, 5 September 2013
Qemu monitor
If your virtual system is running under qmeu then you can access the qemu monitor to interact with that os, various things can be achieved such as sending keystrokes, sending nmi, changing state of the vm, snapshotting, add/remove devices etc.
To gain access to the monitor
ctrl-alt-2
There is a good description of the various options in QEMU-Buch / QEMU-Book, the book is in German but there is an English translation.
To gain access to the monitor
ctrl-alt-2
There is a good description of the various options in QEMU-Buch / QEMU-Book, the book is in German but there is an English translation.
Tuesday, 3 September 2013
Running Raspbian image via qemu on x86_64
While testing some virtualisation configurations I came across mention that it is possible for qemu to run code compiled for different architectures. I was particularly interested in arm, as I could then run some quick testing of Raspberry Pi stuff from my laptop.
So here is how to get Raspbian OS running under qemu.
I needed to install the package containing qemu-system-arm to allow me to run software compiled for arm. I also needed a suitable kernel compiled for arm as well, there are some good instructions located at http://xecdesign.com/compiling-a-kernel/ .
The particular arm cpu I am going to use is arm1176, first double check that this is provided by qemu, it should show up in the list of cpus given by the command
qemu-system-arm -cpu ?
The particular arm machine I am going to use is versatilepb, for a full list of machines run
qemu-system-arm -M ?
Next I need a copy of Raspbian OS image from http://www.raspberrypi.org/downloads, extract from the archive.
To boot the OS I use the following command
qemu-system-arm -kernel <location of kernel for arm> -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1" -hda 2013-07-26-wheezy-raspbian.img
This did not work upon first attempt, this is mentioned on the Raspberry Pi forums. I changed my command to include an additional kernel boot parameter init=/bin/sh, and once booted up I remounted the root filesystem rw and commented out the line in /etc/ld.so.preload.
I restarted the OS using the unmodified command above and it booted.
So here is how to get Raspbian OS running under qemu.
I needed to install the package containing qemu-system-arm to allow me to run software compiled for arm. I also needed a suitable kernel compiled for arm as well, there are some good instructions located at http://xecdesign.com/compiling-a-kernel/ .
The particular arm cpu I am going to use is arm1176, first double check that this is provided by qemu, it should show up in the list of cpus given by the command
qemu-system-arm -cpu ?
The particular arm machine I am going to use is versatilepb, for a full list of machines run
qemu-system-arm -M ?
Next I need a copy of Raspbian OS image from http://www.raspberrypi.org/downloads, extract from the archive.
To boot the OS I use the following command
qemu-system-arm -kernel <location of kernel for arm> -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1" -hda 2013-07-26-wheezy-raspbian.img
This did not work upon first attempt, this is mentioned on the Raspberry Pi forums. I changed my command to include an additional kernel boot parameter init=/bin/sh, and once booted up I remounted the root filesystem rw and commented out the line in /etc/ld.so.preload.
I restarted the OS using the unmodified command above and it booted.
Labels:
arm,
qemu,
RaspberryPi,
Raspbian
Monday, 2 September 2013
Monkey Patching
This was mentioned in passing in a python book I read and I ignored it until I saw it being used to discover the internals of frozen/obfuscated python code.
It is a great term, basically you can overload defined functions with your own code, this is particularly useful for code testing. For example I have seen someone discuss testing an emailing function and rather than send out lots of emails they monkey patch parts of smtplib to add the messages to a dictionary.
A simple example
class orig:
def method1(self):
print "Original method1()"
def method2(self):
print "Original method2()"
if __name__ == "__main__":
obj = orig()
def monkeypatch():
print "Monkey code!"
print "method1()"
obj.method1()
obj.method1 = monkeypatch
print "method1()"
obj.method1()
print "method2()"
obj.method2()
It is a great term, basically you can overload defined functions with your own code, this is particularly useful for code testing. For example I have seen someone discuss testing an emailing function and rather than send out lots of emails they monkey patch parts of smtplib to add the messages to a dictionary.
A simple example
class orig:
def method1(self):
print "Original method1()"
def method2(self):
print "Original method2()"
if __name__ == "__main__":
obj = orig()
def monkeypatch():
print "Monkey code!"
print "method1()"
obj.method1()
obj.method1 = monkeypatch
print "method1()"
obj.method1()
print "method2()"
obj.method2()
Labels:
monkey patching,
python