3

是莽撞人就来单挑:从剪贴板读取图片并保存

 3 years ago
source link: https://yihui.org/cn/2019/10/image-clipboard/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

是莽撞人就来单挑:从剪贴板读取图片并保存

谢益辉 / 2019-10-04


前两天在看一个爆栈网帖子的时候,稍微琢磨了一下如何从剪贴板读取图片。动机是这样:网页上的图片我们都可以点右键复制,然后可以粘贴到别的地方,如 Word 文档,或者在苹果系统的 Preview 应用中从剪贴板新建图片。问题是如此这般复制的图片无法直接粘贴到 R Markdown 文档中。也许将来 RStudio 会支持,那在编辑器支持它之前我们是否有办法先尝试实现它呢?根据我的研究,有两种可能的办法。

在说这两个办法之前,我先说一下我失败的尝试。我知道 R 支持从剪贴板读取数据,如 Windows / Linux 下可以直接 readLines('clipboard'),macOS 下可用管道 pipe('pbpaste') 访问剪贴板,这在帮助文档 ?file 中有详细说明。问题只是,图片是二进制数据,而前面说的办法只能读纯文本数据,比如我们无法使用

file('clipboard', mode = 'rb')

所以此路不通。Windows 下还有个特有的函数 readClipboard(),它可以读入二进制数据,问题只是那个数据如果保存为图片还是个谜,可能还得细究 Windows 文档,我可没那个耐心。两种绕弯的路分别是:

  1. Windows 下可以通过 magick 包(也就是 ImageMagick 移植到 R 包的版本)的函数读取剪贴板的图片:magick::image_read('clipboard:'),有了图片数据之后就可以保存到文件了。Linux / macOS 下的 ImageMagick 不支持读取剪贴板,但可以通过外部工具 xclip 将剪贴板中的图片保存为文件。在 macOS 中可以简单通过 brew install xclip 安装它,Ubuntu 下也就是 apt install xclip,而且这个软件非常轻量级,所以这个依赖问题不大。问题只是它不够智能,需要先检测剪贴板数据格式(MIME 类型),然后再以指定格式保存文件,这个两步过程的第一步可以通过 system2('xclip', ..., stdout = TRUE) 完成(此处有个小坑)。MIME 类型确定后可以通过 R 包 mime 反查扩展名。

  2. 另一种办法是借用 HTML5 的 paste 事件和 event.clipboardData 获取图片数据然后通过 Shiny 把数据读到 R 里面,在 R 里面通过 base64 解码,最后保存图片。这里的 Shiny 可以是一个 RStudio 插件形式的 miniUI 界面。在 blogdown 包中有个 Insert Image 插件,如果前述实现能和这个插件捆绑,那就太完美了,因为用户既可以选择文件上传,也可以直接 Ctrl + V 粘贴图片到这个插件界面中。这条路我不确定是否走得通,主要是我没试过 RStudio 界面里是否支持粘贴事件和剪贴板数据。

只要上面有一条路能走通,剩下的事就是请用户指定一个图片路径,然后我们把剪贴板中的图片保存到这个路径下。这个也可以通过 RStudio 插件实现(类似一个对话框)。

费这么大劲,省下多少力气呢?我们分析一下两种最常见的应用场景:

  1. 从网页复制图片。它节省不了多大工夫,因为网页上的图片点右键既可以复制,又可以直接另存为本地文件。我们上面绕这么大一圈似乎不值得。

  2. 截屏到剪贴板。Windows 下用 Alt + PrtScr、macOS 下用 Cmd + Shift + Ctrl + 4 可将屏幕截图存到剪贴板,然后按上述办法保存为图片文件。如果不这么做,截屏其实也可以直接生成文件,唯一的麻烦就是要重命名并移动图片文件。

回到最初的那个爆栈网帖子。作者真正想节省的似乎是两件事:一是命名文件,二是往 R Markdown 文档中敲 ![](图片路径) 的代码。前者他用了自动的文件命名,后者也是自动生成的,所以往文档中“粘贴”图片被简化成了一次插件点击。我们上面绕弯的办法相比起他的实现来说,优势在于去掉了 Python 依赖,但如果用方法一的话还要引进 xclip 的依赖,无论是 xclip 依赖还是 magick 依赖,都是比较容易安装的。

实际应用中,我个人一般不会用自动文件名,而是会倾向于手工指定一个有意义的文件名,所以他感觉到的便利对我个人的用处可能并不大。所以这个莽撞人项目写出来就当是供路过的客官们练手了。结合 magick 包以及 Shiny 来搭界面玩的话,没准还可以搞出一个简单的 PhotoShop 来哦。

娃的照片 平凡万圣节装扮大赛

Disqus Utterances Preferences

© Yihui Xie 2005 - 2020

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK