phantomjs实现swf Flash转png图片

因为在项目中需要将大量的swf格式的flash文件转换为web图片格式,而且有可能的话还要获取flash中可以点击的按钮的热点位置。

一般的分析流程是swf格式的flash图片需要先反编译才能得到矢量、图片、文字、frame、shape、button、path等信息,然后将反编译后得到的资源进行导出。或者直接对swf运行到最后的显示界面进行截图,这显然是一个很耗时的研究工程。后面发现Sothink SWF Decompiler(硕思闪客精灵)这款软件可以将swf文件批量导出为html5文件,该html5用svg格式图片实现swf的渲染,而且部分swf热点位置在svg中有相关的位置信息,可能可以提取使用。在swf导出h5过程中,除少量swf可能元素太多长时间无法导出外,绝大部分flash图片都能顺利导出一个html5文件和一个sprite.js文件。该h5文件中载入js文件渲染成svg格式的图片。svg是xml格式的数据,因此我们的思路就是将该svg格式图片再转换成我们需要的png图片格式。

html5文件载入js文件执行我们用的是大名鼎鼎的phantomjs 无界面浏览器,获取到svg内容后使用Imagick扩展转换为png图片。以下是代码演示:

首先新建js文件抓取svg的html内容为:

farll.js (去掉script减小页面大小):

var webPage = require('webpage');
var page = webPage.create();
page.open('$fileUrl', function(status) {
window.setTimeout(function () {
    var ct = page.content.replace(/<script[^>]*>(.*?)<\/script>/ig, '');
    console.log(ct);
    page.close();
    phantom.exit();
}, $timeout);
});

$fileUrl是h5文件位置,$timeout是因为swf会设置播放多少秒后完全显示,所以我们需要设置超时,否则会抓取到不完整的页面。

处理脚本我们是用php脚本:

farll.php

ini_set("memory_limit", "2048M");
ignore_user_abort(true);
set_time_limit(0);

// $phantomJsBin是安装的phantomJs的可执行文件的路径
// $output是输出结果的数组,一行一个数组。
// $res是输出结果的最后一行
$res = exec($phantomJsBin . ' farll.js', $output);
$response = implode($output);
unset($output); // 需要清除$output,参见 http://php.net/manual/en/function.exec.php

// 正则匹配svg xml部分,用#代替/则pattern中的html标签不用转义
if(!preg_match('#<svg [^>]+>(.+?)</svg>#ims', $response, $matches)){
// 非贪婪有些匹配不到,再试下贪婪模式:
if(!preg_match('#<svg [^>]+>(.+)</svg>#ims', $response, $matches)) {
// 出错记录日志
file_put_contents($errorPath . $name . '.log', $fileUrl . ':'. $response);
continue;
}
}

// 头部需要加入一行指明svg格式
$headLine = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>';
$svgFile = $svgPath . $name . '.svg';
file_put_contents($svgFile, $headLine . $matches[0]);

//svg转png:
$im = new \Imagick();
$im->readImageBlob(file_get_contents($svgFile));
/*png 设置*/
$im->setImageFormat("png24");
//$im->resizeImage(720, 445, imagick::FILTER_LANCZOS, 1);
/*jpeg 设置*/
//$im->setImageFormat("jpeg");
//$im->adaptiveResizeImage(720, 445);
$im->writeImage($pngPath . $name . '.png');
$im->clear();
$im->destroy();

如果svg转png提示错误:<code>no decode delegate for this image format</code>, 不支持svg格式则需要安装相关依赖。<br ?–>
sudo apt-get install php5-imagick
php -i | grep ImageMagick supported formats 没有svg。
有文章指出安装以下依赖,但是仍然提示不支持:
sudo apt-get install librsvg2-bin 和 libxml2。
需要安装ImageMagick:
sudo apt-get install ImageMagick另外下载安装phantomjs到官网下载相应系统版本即可:
wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
在ubuntu14.04开发环境下跑完后发现有少部分hmtl5,可能是因为太大导致内存越界的原因,page.open后一直显示:
PhantomJS has crashed. Please read the bug reporting guide at
<http://phantomjs.org/bug-reporting.html> and file a bug report.
Segmentation fault (core dumped)
在命令行环境执行,排除框架使用纯php执行都没能解决。

最后只能换到windows环境下执行。
下载php: windows.php.net/downloads/releases/php-5.6.32-nts-Win32-VC11-x64.zip
下载imagick dll:pecl.php.net/package/imagick/3.4.3/windows

imagick 配置步骤有点多
1. 复制php_imagick.dll到php扩展目录并在php.ini 中启用扩展:
extension=G:/php56/ext/php_imagick.dll
2. 执行 G:\php56\php.exe -e -v 会提示缺少DDL的错误,将imagick扩展中缺少的DDL复制到php56的安装目录下。
3. 执行 G:\php56\php.exe -i 查看 phpinfo信息,确保其中显示的 ImageMagick 版本和下面要下载的版本是一致的。
4. 下载安装相应版本的ImageMagick:ftp.icm.edu.pl/packages/ImageMagick/binaries/ImageMagick-6.9.3-7-Q16-x64-dll.exe
5. 关闭cmd窗口重新打开即可。

最后cmd执行脚本
set RUNTIME_ENVIROMENT=localhost //如果需要设置环境变量的话
G:\php56\php.exe farll.php -mMethodName //如果需要额外传入参数的话

至于可以点击的热点,用domdocument解析xml抓取特征数据即可. 循环过程中应该用load($file)或loadXml($xmlString), 错用了loadHtml将会产生大量错误信息,内存不释放而导致进程被kill掉,这种情况下可以设置libxml_use_internal_errors(true) 为false或每次循环后清除error 日志: libxml_clear_errors().

后面发现部分字体在linux下生成时没有呈现,部分文字消失。 在win环境下会提示缺少字体文件:
** (php.exe:5424): WARNING **: couldn’t load font “ft8741 Not-Rotated 0.91992187
5”, falling back to “Sans Not-Rotated 0.919921875”, expect ugly output.

因此可以尝试下在windows下再去生成一次。

Leave a Reply

Your email address will not be published. Required fields are marked *