跳转至

通过代码捕获IDL图形用户界面屏幕截图

原文链接: https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/screen-capturing-idl-guis-from-code

10422 为本文评分:

5.0

通过代码捕获IDL图形用户界面屏幕截图

Jim Pendleton 2015年10月29日 星期四

用户长期以来一直期望能够在IDL环境中以编程方式捕获IDL部件(widget)的屏幕截图。

遗憾的是,这一功能短期内似乎无法实现,因此我一直在互联网上搜寻可能的变通方案。

Linux系统

在Linux系统上,长期以来可以直接通过SPAWN调用ImageMagick的"import"命令行应用程序。

如果imagemagick套件已包含在系统路径中,您可以捕获整个显示屏幕,或捕获指定名称的单个窗口。

屏幕截图会保存到临时文件,随后可将其读入IDL。以下示例假设imagemagick的"import"可执行文件位于shell路径中。


IDL> spawn, 'import -window root screenshot.jpg', output, error

IDL> im = read_jpeg('screenshot.jpg')

IDL> i = image(im)

IDL> file_delete, 'screenshot.jpg'

ImageMagick已存在很长时间。您可以根据系统管理员允许的程度来决定对其的信任度。

对于Linux用户而言,这是一个可行的解决方案,且无需修改IDL内部代码来支持此功能。

Windows系统

在Windows系统上,如果同时运行Cygwin X服务器,ImageMagick似乎也能实现此功能。

但既然有更简单的解决方案,谁还愿意处理那些复杂配置呢?

我最近在github上发现了Vasil Arnaudov提供的嵌入式C#简单DOS批处理脚本,为Windows用户提供了等效功能,无需安装来源可疑、意图不明或受版权限制的"免费软件"。

您可以阅读源代码并自行决定是否信任。

唯一的要求是已安装.NET框架——对于任何比XP更新的Windows版本来说,这几乎是必然已安装的。

在本示例中,我先将Vasil Arnaudov的"screenCapture.bat"复制到Windows桌面再执行。





 

IDL> spawn, 'c:\users\me\desktop\screenCapture.bat test.png', output, error
IDL> im = read_png('test.png')
IDL> i = image(im[0:2, *, *])
IDL> file_delete, 'test.png'

由于选择捕获PNG格式,我还获取了透明度通道,因此第一个维度是4个元素(RGBA)而非3个(RGB)。

您可以选择其他格式如JPEG或BMP进行捕获。可通过查阅源代码了解支持的文件格式选项。

假设我只想捕获单个部件的内容。


IDL> tlb = widget_base(/column, xoffset=100, yoffset=200, title='my widget')

IDL> l = widget_label(tlb, value='我们将捕获此部件的内容')

IDL> widget_control, tlb, /realize

在捕获全屏之前,可随意将部件移动到屏幕上的新位置。


IDL> spawn, 'c:\users\me\desktop\screenCapture.bat test.jpg', output, error

IDL> read_jpeg, 'test.jpg', im

IDL> i2 = image(im)

IDL> file_delete, 'test.jpg'

理论上,screenCapture.bat可接受窗口名称作为可选参数,仅捕获该窗口。但在IDL测试中,我发现焦点常常(并非总是)会返回到主IDL工作台,导致捕获的是该窗口而非目标部件。

那么,如何从全屏截图中提取仅包含我们部件的内容呢?

请注意,我们的屏幕截图图像原点在左下角,但屏幕偏移量是从左上角开始测量的。利用WIDGET_INFO返回的几何信息结构,定位并提取部件的位图。


IDL> g = widget_info(tlb, /geometry)

IDL> s = get_screen_size()

IDL> ox = g.xoffset

IDL> oy = s[1] - g.yoffset

IDL> w = im[*, ox:ox + g.scr_xsize, (oy - g.scr_ysize):oy]

IDL> i = image(w)

如果您使用多显示器,并希望捕获主显示器之外的其他显示器图像,可能需要修改提供的C#代码——这留给读者作为练习。

当然,这个逻辑可以轻松封装成函数,接受部件ID作为输入,返回图像数组作为输出。这也留给读者作为练习。

创建高质量镶嵌图的技巧 自动云和云阴影检测