使用Perl的IPC::Run调用AppleScript操作Mac剪贴板PNG数据报错
问题描述
我的最终目标是:
- 在MacOS上从剪贴板获取PNG数据
- 对其进行处理(通常使用ImageMagick)
- 将处理后的数据放回剪贴板
我尝试通过Perl的IPC::Run实现该功能。
AppleScript的最简示例可正常运行:
set in_clip to get the clipboard as «class PNGf» set the clipboard to in_clip as «class PNGf»
该示例无报错,且不会修改剪贴板内容。
但当我用Perl编写逻辑相同的代码时:
use IPC::Run qw/run/; use utf8; $\ = "\n"; $, = "\t"; my ($stdin, $stdout, $stderr); run ["osascript", "-e", "get the clipboard as «class PNGf»"], \$stdin, \$stdout, \$stderr; print ("original data:", (substr $stdout, 0, 100) . "..." . (substr $stdout, -200)) ; run ["osascript", "-e", (sprintf qq(set the clipboard to "%s" as «class PNGf»), ($stdout =~ s/\n//gmrs))], \$stdin, \$stdout, \$stderr; print ("convert error:", (substr $stderr, 0, 100) . (substr $stderr, -200)) ;
却出现错误:
convert 64548:64560: execution error: Can’t make "«data PNGf89504E4...26082»" into type «class PNGf»
请问这是什么原因?我知道这种实现方式比较繁琐且处于技术边缘,但为何会报错?
原因分析与解决
核心问题
你通过osascript获取到的$stdout是字符串形式的AppleScript数据表示(比如«data PNGf89504E4...»),而不是原始的二进制PNG数据。当你把这个字符串用双引号包裹传给AppleScript时,它只会把这当作普通文本字符串,无法自动解析成«class PNGf»类型的数据,所以报错。
AppleScript直接赋值时,in_clip是原生的PNFf类型对象,但Perl传递的是该对象的字符串化描述,两者本质不同。
正确的实现思路
要在Perl和AppleScript之间传递二进制PNG数据,应该避免字符串化,直接通过标准输入输出传递原始二进制流:
- 用AppleScript导出剪贴板的原始PNG二进制数据到stdout
- Perl读取二进制数据,交给ImageMagick处理
- 将处理后的二进制数据通过stdin传给AppleScript,写入剪贴板
修改后的代码示例
use IPC::Run qw/run/; use utf8; # 1. 从剪贴板读取原始PNG二进制数据 my $png_data; run ["osascript", "-e", 'get the clipboard as «class PNGf»'], undef, \$png_data; # 2. 这里添加ImageMagick处理逻辑,示例:转为灰度图(可按需修改) my $processed_data; run ["convert", "-", "-colorspace", "Gray", "png:-"], \$png_data, \$processed_data; # 3. 将处理后的二进制数据写回剪贴板 run ["osascript", "-e", 'set the clipboard to (read stdin as «class PNGf»)'], \$processed_data;
关键注意点
- 不要对二进制数据做任何字符串处理(比如
s/\n//gmrs),否则会破坏原始PNG的二进制结构 - Perl变量要能正确保存二进制数据,避免使用会自动转码的字符串处理函数
内容的提问来源于stack exchange,提问作者simone
相关产品推荐
相关产品推荐

