Magic PNG&canvas

孟红伦

i@allenm.me

2010/10

一、动态 favicon

有没有想过通过js来动态改变favicon?比如在favicon上显示未读邮件数。

这个chrome插件实现了在主流WEB应用的favicon中显示未读数。

那么是怎么实现的呢?

在 favicon 上显示当前日期
DEMO
IE系全部不支持
chrome, firefox, opera 支持
WIN版safari:如果页面的 onload 事件发生的比更改favicon晚一会儿,则起效。DEMO for safari on windows

via remy sharp's b:log

在 favicon 上显示任意字符
DEMO

chrome, opera, firefox中可用

在 favicon 上玩游戏
DEFENDER

老外真是疯狂 :)    玩此游戏时,如果你的电脑和我的一样破,
你会听到风扇的呼呼声

二、用PNG图片来打包 js 文件

能不能把字符串信息写入PNG图片,然后前端获取图片后,
对图片进行解码呢?

PNG图片特性
  • Lossless data compression(very important!)
  • 主流浏览器都兼容它
  • 主流编程语言图形库的支持
  • 常用PNG8 和 PNG24 两种模式
  • Read More  WIKI    PNG Home Site
从PNG图片里能获得到什么样的数据呢?

又轮到 canvas 发威了!

让我们看看context.getImageData() 这个函数能返回给我们什么吧

另外不要忘记 js 有个 fromCharCode() 方法。

使用方法 String.fromCharCode(num,num,num...) 。

根据unicode编码返回字符串

字符串打包进PNG

我们有办法获取到图片每个像素的 RGBA 值,而且每个值都是不大于256的数字。

我们又有办法根据一个数字返回unicode中它对应的字符。

现在你知道该怎么把字符串打包进PNG了吗?

一个用PHP实现的较简单方法
header("Content-type: image/png");
$path=$_GET['path'];
if($path){
	encode_file($path);
}

function encode_file($path){
	$data = file_get_contents($path);
	$size = strlen($data);
	#
	# the simplest method is to store the bytes as they are in ascii.
	# this is the least space-efficient.
	#
	$bytes = array();
	for ($i=0; $i<strlen($data); $i++){
		$bytes[] = ord(substr($data, $i, 1)); 
# @mdthod ord || int ord ( string $string ) 
# Returns the ASCII value of the first character of string . 
	}
	encode_bytes($bytes);
}
				
function encode_bytes($bytes){
	$size = count($bytes);
	$px = ceil($size / 3);
	$w = floor(sqrt($px));
	$h = ceil($px / $w);
	
	$im = imagecreatetruecolor($w, $h);
	imageAlphaBlending($im, false);
	imageSaveAlpha($im, false);
	
	$i=0;
	for ($y=0; $y<$h; $y++){
		for ($x=0; $x<$w; $x++){

			$b1 = $bytes[($i*3)+0];
			$b2 = $bytes[($i*3)+1];
			$b3 = $bytes[($i*3)+2];
			$col = imagecolorallocate($im, $b1, $b2, $b3);
			imagesetpixel($im, $x, $y, $col);

			$i++;
		}
	}
	imagepng($im);
	imagedestroy($im);
}
				

又到看 DEMO 的时间了。

这种方式显然不支持编码中文,因为中文在unicode中编码有两个字节长

但是肯定有实现方式,有兴趣的话,你来实现吧 :)

下面是我们的 fdev.js 按照此方式编码后的图。

<img src="./packstream.php?path=
http://style.china.alibaba.com/js/lib/fdev-v3/core/fdev-min.js" alt="fdev" />
			
fdev

这个方法有什么用处呢?

因为浏览器加载外域的图片并没有限制,
那我们能不能通过这个做跨域异步请求呢?

是不是开始期待我来 show 一下用图片做跨域了?

可是我要说:我无法做到

读取图片数据也有浏览器安全策略限制,来看 DEMO

想了解更多把字符串打包进PNG图片的方法

请关注:PNGStore

FAQ