使用GTK截取屏幕子区域的截图
我正在尝试在Ubuntu 10.04上使用Python只截取屏幕的一部分。
这是我的代码(假设IMAGE_GRAB
是False):
def screenshot_roi(regions):
if IMAGE_GRAB:
return map(ImageGrab.grab, regions)
else:
w = gtk.gdk.get_default_root_window()
sz = w.get_size()
pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1])
src = pb.get_from_drawable(w,w.get_colormap(),0,0,0,0,sz[0],sz[1])
results = []
for roi in regions:
if not roi:
results.append(None)
continue
x,y,width,height = roi
dst = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,width,height)
src.copy_area(x,y,width,height,dst,0,0)
im = PIL.Image.fromstring("RGB", (width, height), dst.get_pixels())
results.append(im)
return results
这里没有什么特别的。它会把整个可绘制区域捕捉到一个像素缓冲区中,然后再对每个像素缓冲区进行裁剪,最后把它转换成需要的PIL对象。
这是主要的代码部分:
def main():
regions = [(845, 219, 248, 82), (1101, 243, 109, 59),
(1213, 245, 66, 57), (1281, 245, 74, 58)]
images = screenshot_roi(regions)
for i,roi in enumerate(images):
if roi:
roi.save('%d.png' % i)
if __name__ == '__main__':
main()
不过,生成的图像(除了第一张)都有一些步幅问题:
1:
2:
3:
4:
现在,如果我在PIL中进行裁剪,一切都能正常工作:
def screenshot_roi(regions):
if IMAGE_GRAB:
return map(ImageGrab.grab, regions)
else:
w = gtk.gdk.get_default_root_window()
sz = w.get_size()
pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1])
src = pb.get_from_drawable(w,w.get_colormap(),0,0,0,0,sz[0],sz[1])
entire_im = PIL.Image.fromstring("RGB", sz, src.get_pixels())
results = []
for roi in regions:
if not roi:
results.append(None)
continue
x,y,width,height = roi
crop = entire_im.crop((x,y,x+width,y+height))
crop.load()
results.append(crop)
return results
不过,我不想这样做,因为从GTK转换到PIL的过程相当耗费资源。这样做很浪费,因为我把整个图像都转换了,只是为了获取一些小的子区域。
有没有人能建议一下为什么GTK版本会出现步幅错误?
编辑
有效的源代码:
x,y,w,h = region
win = gtk.gdk.get_default_root_window()
pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,w,h)
src = pb.get_from_drawable(win,win.get_colormap(),x,y,0,0,w,h)
im = PIL.Image.frombuffer('RGB', (w,h), src.get_pixels(), 'raw',
'RGB', src.get_rowstride(), 1)
return im
1 个回答
4
我觉得这是因为get_pixels这个函数返回的数据是按照它在内存中存储的方式来的。你需要注意的是,一行数据的末尾可能会有一些额外的空间,这主要是为了提高性能(因为内存对齐的要求)。
可以看看GdkPixbuf结构:这里面有个很重要的信息叫做rowstride,它表示一行的开始和下一行的开始之间的字节数。这个值等于一行中的数据字节数加上额外的填充字节数。
要注意的是最后一行是没有填充的。