1.背景
现有信息系统左上角有一个swf格式的logo,是简单的文字特效类效果。由于高版本的谷歌内核浏览器不再内置Flash播放器,所以导致谷歌内核浏览器打开系统后,logo区域一片灰色,只有"该插件不受支持的提示"。
2.需求
该动态文字效果的logo在IE和谷歌内核浏览器上均能显示,并且依然保持背景透明。
3.方案
3.1 废弃方案
- 使用Flash导出为gif: 锯齿超级严重;
- 使用Flash导出为视频:无法实现背景透明;
- 使用Flash导出为gif,再使用PS逐帧去除锯齿:费时费力。
- 使用Canvas直接绘图,实现动态效果:无法实现
总结:因为gif本身格式的限制,注定了使用gif图片无法实现高清晰度的展示。而使用Canvas直接绘制,根本不可能实现flash那炫酷丝滑的效果。
3.2 完美方案
- 使用 Flash 把 swf 转为 png 序列图
- 编写 python 脚本将序列图拼接为1张 png 格式 Sprite图
- 使用JavaScript在Canvas中不断绘制 png 图
4.效果
该动画效果仅是在文字的表面模拟光照划过的闪光效果。制作GIF动图不方便,此处截图对比作为参考。
可以看到效果非常完美,和Flash一样的清晰流畅。
5. 实操
1. 使用Flash Profession CS6 将 SWF 导出为 PNG序列图
2. 查看导出的序列图
总共50个图,大小一致,均是 600*100(即舞台背景的大小),背景透明。
3. 编写python脚本拼接序列图
其实也可以在PS里,手动一个个拼接。写Python脚本也挺费时间。
使用该Python脚本将 50 个 600*100 的 png 拼接成一个 10行5列,大小为 3000*1000 的单一 png 图片,背景透明。
下面是拼接 50 张 png 的 Python3代码:
注:需使用CMD命令:pip install pillow 提前安装Python3的图形库 PIL 。关于PNG的打开和粘贴等处理不明白的可参考我之前的博文或自行搜索。
# make pngs to sprite
# 注意:我的PNG图片存放在 png_seq 文件夹内,本脚本存放在
# 与 png_seq 文件夹同级别的目录里
from PIL import Image, ImageDraw, ImageFont
# sprite 对象
sprite = Image.new(mode='RGBA', size=(3000, 1000))
line,column = 10,5 # 粘贴成 10行5列
pngw,pngh = 600,100 # 每个png图片的宽高
# create file name
def fname(i):
if i < 10:
return 'wh000' + str(i) + '.png'
else:
return 'wh00' + str(i) + '.png'
# 打开 PNG 图片序列,位置 png_seq/wh0001到wh0050.png
for x in range(1,51):
pngfile = 'png_seq/'+ fname(x)
png = Image.open(pngfile).convert('RGBA')
r,g,b,a = png.split()
lineIndex = int( (x-1)/ 5)
columnIndex = (x-1) % 5
print(columnIndex)
#粘贴的位置坐标 左上角x,y 右下角x,y
box= (600*columnIndex, 100*lineIndex, 600*columnIndex+600, 100*lineIndex+100)
sprite.paste(png, box, png) #参数3是alpha通道
# 保存结果
output = 'sprite.png'
sprite.save(output, 'png', quality = 100)
4. 在html/jsp 页面编写Javascript代码绘制动画
该代码可实现:自动检测浏览器是否支持 canvas。如果支持canvas,就使用JS绘图。如果不支持,就退化为播放 Flash。
代码里面用到了一点点 JQuery 。
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<div id="banner" >
<embed id="bannerSwf" src="images/logo.swf" width="600" height="100" quality="high" wmode="transparent" type="application/x-shockwave-flash"/>
<canvas id="bannerCanvas"></canvas>
</div>
</body>
<script type="text/javascript">
//----banner使用Canvas绘制--开始----
$(document).ready(function(){
//逐帧绘制Sprite
var bannerAnimate = function(){
var canvas = document.getElementById("bannerCanvas");
var ctx = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 100;
var img = new Image();
img.src = "sprite.png"; //加载精灵图sprite
img.onload = function(){
var pngNum = 0; //帧序号
var colIndex = 0;
var lineIndex = 0;
setInterval(function(){
ctx.clearRect(0,0,canvas.width,canvas.height);
lineIndex = parseInt(pngNum / 5);
colIndex = pngNum % 5;
ctx.drawImage(
img,
colIndex * 600, //截取精灵图的每一帧
lineIndex * 100, //截取精灵图的每一帧
600,
100,
0,
0,
600,
100
);
pngNum ++;
pngNum %= 50; //1~50循环播放
}, 600/10) //播放速度
}
};
//检测浏览器是否支持Canvas
try{
document.createElement("canvas").getContext("2d");
$('#bannerSwf').hide();
$('#bannerCanvas').show();
bannerAnimate(); //用Canvas绘制图片帧
}catch(e){
$('#bannerSwf').show(); //不支持Canvas
$('#bannerCanvas').hide();
}
});
//----banner使用Canvas绘制--结束----
</script>
</html>
下面是关键方法 drawImage()方法的说明。
参数 | 描述 |
---|---|
img | 规定要使用的图像、画布或视频。 |
sx | 可选。开始剪切的 x 坐标位置。 |
sy | 可选。开始剪切的 y 坐标位置。 |
swidth | 可选。被剪切图像的宽度。 |
sheight | 可选。被剪切图像的高度。 |
x | 在画布上放置图像的 x 坐标位置。 |
y | 在画布上放置图像的 y 坐标位置。 |
width | 可选。要使用的图像的宽度。(伸展或缩小图像) |
height | 可选。要使用的图像的高度。(伸展或缩小图像 |
全文完。