图片怎么转为html5,将图片转化为矢量并canvas化的容易工具(基于Node.js + HTML5 canvas)...

将图片转化为矢量并canvas化的简单工具(基于Node.js + HTML5 canvas)

一、前言

最近需要做一个图标的矢量化,但是没有数据,因此采用了node.js作为数据处理工具,canvas绘制图标;结果发现使用canvas绘制的图标比之前少了近10几k(原20K+, 现包含代码10k-);所以结果还是比较近人意的。代码已经放在github了,具体戳这:https://github.com/vczero/image-vector 欢迎大家改进,这只是个so simple tool...

二、设计

(1)做一个基本的矢量数据处理工具,方便后期数据生产较为自动化;

(2)选用node.js作为批量数据处理的脚本工具,暴露服务接口,前端调用;canvas按照图层要素渲染;

三、产出

(1)canvas绘制携程的图标(不是图片,是json数据),如下。可以访问:http://vczero.github.io/ctrip/index.html;

185808156.png

(2)简单的矢量化处理工具,如下图:

185808157.png

四、node.js服务端

node.js主要作为数据处理服务存在,具体的代码很简单,如下:

(0)服务接口如下:

1 /*

2 * 路由服务列表模块3 *4 **/

5 var routes = require('./index');6 var create = require('./create');7 var get = require('./get');8 var compile = require('./compile');9 var dir = require('./dir');10 var contact = require('./contact');11 var dist = require('./dist');12

13

14 module.exports = function(app){15

16 //index, 服务列表

17 app.use('/', routes);18

19 //des:创建点文件

20 //@x:横坐标

21 //@y:纵坐标

22 //@fileName:需要保存的文件名

23 //url: domain/create?x=112&y=678&fileName=polygon_text

24 app.get('/create', create);25

26 //des:获取目录下指定json文件的json对象

27 //@dirName:

28 //@fileName:

29 //url: domain/get?dirName=json&fileName=polygon_text

30 app.get('/get', get);31

32 //des:将点数据转化成可用坐标数据

33 //@fileNames:当isMany传入参数为1的时候,fileNames=file1@file2@file2的形式;否则只为fileNames=fileName

34 //[@isMany]:当需要处理多文件的时候传入

35 //url:domain/compile?fileNames=xxx[&isMany=1]

36 app.get('/compile', compile);37

38 //des:列出目录下面的文件

39 //@dirName:目录名称

40 //url:domain/dir?dirName=xxx

41 app.get('/dir', dir);42

43 //des:数据合并

44 //@fileNames:多文件,以@分割,例如fileNames=file1@file2@file2

45 app.get('/contact', contact);46

47 //des:数据压缩

48 //@fileName需要压缩的文件名

49 //url:domain/dist?fileName=xxx

50 app.get('/dist', dist);51

52 };

(1)获取某个文件夹下的某个文件:

1 /*

2 * 描述:读取json文件的json对象, 这里因为实时读取建议不使用require加载3 * 时间:2015-04-144 **/

5

6 var fs = require('fs');7

8 module.exports = function(req, res){9 var dirName = req.param('dirName');10 var fileName = req.param('fileName');11 var errStatus = {status: 0};12

13 if(!dirName || !fileName){14 returnres.json(err);15 }16

17 var path = './' + dirName + '/' + fileName + '.json';18

19 fs.readFile(path, function(err, data){20 try{21 var reObj = null;22 var obj =JSON.parse(data.toString());23 reObj ={24 status: 1,25 data: obj26 }27 }catch(e){28 reObj = null;29 }30

31 if(!err &&obj){32 returnres.json(reObj);33 }else{34 returnres.json(errStatus);35 }36 });37 };

(2)创建点位数据

1 /*

2 * 描述:向文件中追加坐标3 * 时间:2015-04-144 **/

5 var fs = require('fs');6

7 module.exports = function(req, res){8 var x = req.param('x');9 var y = req.param('y');10 var fileName = req.param('fileName');11 var str = x + '\t' + y + '\r\n';12

13 fs.appendFile('./data/' + fileName, str, function(err){14 var obj ={15 x: x,16 y: y17 }18 if(!err){19 obj.status = 1;20 res.json(obj);21 }else{22 obj.status = 0;23 res.send(obj);24 }25 console.log('saved: ', x + ' , ' +y);26 });27

28

29 }

(3)将数据转化为可用的json格式数据

1 /*

2 * 描述:将数据转化为可用的json3 * 时间:2015-04-144 **/

5

6 var fs = require('fs');7 var parseData = function(data){8 var strs = (data.toString()).split('\r\n');9 var data =[];10 for(var i = 0; i < strs.length; i++){11 var xys = strs[i].split('\t');12 var xy ={13 x: xys[0],14 y: xys[1]15 };16 if((i + 1) !==strs.length)17 data.push(xy);18 }19 var obj =data;20 returnobj;21 };22

23 module.exports = function(req, res){24 var fileNames = req.param('fileNames');25 var isMany = req.param('isMany');26 var pathData = '';27 var pathJSON = '';28

29 //单文件处理

30 if(!isMany){31 pathData = './data/' +fileNames;32 pathJSON = './json/' + fileNames + '.json';33 fs.readFile(pathData, function(err, data){34 var obj =parseData(data);35 fs.writeFile(pathJSON, JSON.stringify(obj), function(err){36 if(!err)37 returnres.json(obj);38 else

39 return res.json({status: 0});40 });41 });42 }else{//多文件处理

43 var names = fileNames.split('@');44 try{45 for(var i innames){46 var path_Data = './data/' +names[i];47 var path_JSON = './json/' + names[i] + '.json';48 var content =fs.readFileSync(path_Data);49

50 fs.writeFileSync(path_JSON, JSON.stringify(parseData(content)));51 }52 res.json({status: 1});53 }catch(e){54 res.json({status: 0});55 }56 }57 }

(4)列目录

1 /*

2 * 描述:列目录3 * 时间:2015-04-144 **/

5

6 var fs = require('fs');7

8 module.exports = function(req, res){9 var dirName = req.param('dirName');10 fs.readdir('./' + dirName, function(err, files){11 if(!err){12 returnres.json({13 status: 1,14 files: files15 });16 }17 return res.json({status: 0});18

19 });20 };

(5)多个json文件合并

1 /*

2 * 描述:数据合并3 * 时间:2015-04-144 **/

5

6 var fs = require('fs');7 module.exports = function(req, res){8 var fileNames = req.param('fileNames');9 var pathContact = './contact/';10 var names = fileNames.split('@');11

12 try{13 var content =[];14 for(var i innames){15 var pathData = './json/' +names[i];16 var data =fs.readFileSync(pathData);17 var name = names[i].split('.')[0];18 var obj ={};19 obj[name] =JSON.parse(data.toString());20 content.push(obj);21

22 }23 var files =fs.readdirSync(pathContact);24 var newName = 'contact_';25 if(files.length){26 var n =files.length;27 newName += (parseInt(n) + 1) + '.json';28 }else{29 newName += '1.json';30 }31 var str =JSON.stringify(content);32 fs.writeFile(pathContact + newName, str, function(err){33 if(!err)34 res.json({status: 1});35 });36 }catch(e){37 res.json({status: 0});38 }39

40 }

(6)去除冗余的数据

1 var fs = require('fs');2

3 module.exports = function(req, res){4 var fileName = req.param('fileName');5 var errStatus = {status: 0};6

7 if(!fileName){8 returnres.json(errStatus);9 }10

11 var path = './contact/' + fileName + '.json';12 fs.readFile(path, function(err, data){13 if(!err){14 var arr =JSON.parse(data.toString());15 //TODO:Format && compare

16 //第一层

17 var result ={};18 for(var i inarr){19 var obj =arr[i];20 //第二层

21 for(var n inobj){22 var dataXYs =obj[n];23 result[n] =[];24 //第三层

25 for(var k indataXYs){26 result[n].push(dataXYs[k].x);27 result[n].push(dataXYs[k].y);28 }29 }30 }31 //写入到压缩文件夹

32 var files = fs.readdirSync('./dist/');33 var newFileName = 'dist_';34 if(files.length){35 var n =files.length;36 newFileName += (parseInt(n) + 1) + '.json';37 }else{38 newFileName += '1.json';39 }40 fs.writeFile('./dist/' + newFileName, JSON.stringify(result), function(err){41 if(!err){42 var sizeOld =fs.statSync(path).size;43 var sizeNew = fs.statSync('./dist/' +newFileName).size;44 var reObj ={45 status: 1,46 //压缩率计算

47 rate: (sizeOld - sizeNew)/sizeOld,

48 //新文件名

49 filename: newFileName,50 //压缩结果

51 data: result52 }53 returnres.json(reObj);54 }55 returnres.json(errStatus);56 });57 }else{58 returnres.json(errStatus);59 }60 });61

62

63 }

五、canvas绘制

(1)封装了个简单的ajax工具类

185808158.gif

185808159.gif

1 /*

2 * 描述:提供基本的AJAX、JSON、事件绑定3 * 时间:2015-04-144 **/

5 ;(function(exports){6

7 //JSON

8 functionjsonParse(data){9 if(JSON){10 returnJSON.parse(data);11 }else{12 return (new Function('return' +data))();13 }14 }15

16 //AJAX

17 functionajax(options, callback){18 var method = options.method || 'GET';19 var url = options.url || '';20 var xmlHttp = null;21

22 if(window.XMLHttpRequest){23 xmlHttp = newXMLHttpRequest();24 }25

26 if(window.ActiveXObject){27 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");28 }29

30 xmlHttp.open(method, url, true);31 xmlHttp.onreadystatechange = function(){32 if(xmlHttp.readyState === 4 && xmlHttp.status === 200){33 callback(jsonParse(xmlHttp.responseText));34 }35 }36 xmlHttp.send();37 }38

39 //事件绑定

40 functionaddEvent(el, type, callback){41 if(!el){42 return;43 }44 if(el.addEventListener){45 el.addEventListener(type, callback);46 }else{47 el.attachEvent('on' +type, callback);48 }49 returncallback;50 }51

52 //Tip

53 var ID_STRING = '_____wlh_tip___0088';54 functiontipShow(){55 var body = document.getElementsByTagName('body')[0];56 if(document.getElementById(ID_STRING)){57 document.getElementById(ID_STRING).style.display = 'block';58 body.style.overflow = 'hidden';59 return;60 }61 var el = document.createElement('div');62 el.style.zIndex = 1000;63 el.style.width = '300px';64 el.style.height = '150px';65 el.style.backgroundColor = '#FFF';66 el.style.position = 'fixed';67 el.style.left = '30%';68 el.style.top = '40%';69 el.style.opacity = 0.9;70 el.style.color = '#00B7FF';71 el.style.lineHeight = '150px';72 el.style.fontSize = '16px';73 el.style.paddingLeft = '20px';74 el.style.borderRadius = '3px';75 el.innerHTML = '数据正在处理, 请等待......';76 el.id =ID_STRING;77

78 body.style.overflow = 'hidden';79 body.appendChild(el);80 return;81 }82

83 functiontipHide(){84 var body = document.getElementsByTagName('body')[0];85 if(document.getElementById(ID_STRING)){86 document.getElementById(ID_STRING).style.display = 'none';87 body.style.overflow = 'auto';88 }89 }90

91 exports.ajax =ajax;92 exports.addEvent =addEvent;93 exports.tipShow =tipShow;94 exports.tipHide =tipHide;95

96 })(window);

View Code

(2)canvas图层叠加绘制

1 ;(function(exports, require){2 var canvas = document.getElementsByTagName('canvas')[0];3 var context = canvas.getContext('2d');4 var ajax =require.ajax;5 var addEvent =require.addEvent;6

7 //缩放比例

8 var SCALE_BIG = 1;9 var SCALE_SML = 0.25;10

11 //颜色对应表

12 var COLOR_LIST ={13 BODY: '#63CEF6',14 DUPI: '#FFF',15 EYE: '#034E68',16 ZUIBA: '#0089B5',17 TOUQUAN: '#BDF9FB',18 JIUWO: '#FFBFE3',19 QIPAO: '#C9E8FB',20 BISHANG: '#46BEEF',21 BIXIA: '#54C5F2',22 GO: '#B1DBF2'

23 };24

25 if(!context){26 return;27 }28

29 context.scale(SCALE_SML, SCALE_SML);30

31 //simple package design pattern

32 functionaddDrawFunc(data, part, color, fun){33 var xys =data[part];34 context.beginPath();35 context.strokeStyle =color;36 context.lineWidth = 1;37 context.fillStyle =color;38 fun(xys);39 context.stroke();40 context.fill();41 context.closePath();42 }43 //draw polygon

44 functiondrawPolygon(data, part, color){45 addDrawFunc(data, part, color, function(xys){46 context.moveTo(xys[0], xys[1]);47 for(var i = 2; i < xys.length; i++){48 if(i % 2 !== 0){49 context.lineTo(xys[i-1], xys[i]);50 }51 }52 });53 }54

55 //draw eye

56 functiondrawEye(data, part, color){57 addDrawFunc(data, part, color, function(xys){58 //变形

59 context.save();60 context.scale(1.5, 2);61 context.arc(xys[0]/1.5, xys[1]/2, 6, 0, Math.PI * 2, false);62 context.restore();63 });64 }65

66 //drawCircle

67 functiondrawCircle(data, part, color, radius){68 addDrawFunc(data, part, color, function(xys){69 context.arc(xys[0], xys[1], radius, 0, Math.PI * 2, false);70 });71 }72

73

74

75 //draw line

76 functiondrawLine(data, part, color, width){77 var xys =data[part];78 context.beginPath();79 context.strokeStyle =color;80 context.lineWidth =width;81 context.moveTo(xys[0], xys[1]);82 for(var i = 0; i < xys.length; i++){83 if(i % 2 !== 0){84 context.lineTo(xys[i-1], xys[i]);85 }86 }87 context.stroke();88 context.closePath();89 }90

91 //draw text

92 functiondrawText(x, y){93 context.beginPath();94 context.fillStyle = '#FFFFFF';95 context.font = '40px arial,sans-serif';96 context.fillText('go...', x, y)97 context.fill();98 context.closePath();99 }100

101

102 //绘制

103 functiondraw(fileName){104 var url = 'http://127.0.0.1:3000/get?dirName=dist&fileName=' +fileName;105 ajax({method: 'GET', url: url}, function(data){106 data =data.data;107 drawPolygon(data, 'polygon_body', COLOR_LIST.BODY);108 drawPolygon(data, 'polygon_dupi', COLOR_LIST.DUPI);109 drawPolygon(data, 'polygon_touquan', COLOR_LIST.TOUQUAN);110 drawPolygon(data, 'polygon_jiuwo1', COLOR_LIST.JIUWO);111 drawPolygon(data, 'polygon_jiuwo2', COLOR_LIST.JIUWO);112 drawPolygon(data, 'polygon_go', COLOR_LIST.GO);113

114 drawEye(data, 'circle_eye1', COLOR_LIST.EYE);115 drawEye(data, 'circle_eye2', COLOR_LIST.EYE);116

117 drawLine(data, 'line_zui', COLOR_LIST.ZUIBA, 4);118 drawLine(data, 'line_bishang', COLOR_LIST.BISHANG, 8);119 drawLine(data, 'line_bixia', COLOR_LIST.BIXIA, 5);120

121 drawCircle(data, 'circle_qipao1', COLOR_LIST.QIPAO, 30);122 drawCircle(data, 'circle_qipao2', COLOR_LIST.QIPAO, 25);123 drawCircle(data, 'circle_qipao3', COLOR_LIST.QIPAO, 15);124 drawCircle(data, 'circle_qipao4', COLOR_LIST.QIPAO, 20);125 drawCircle(data, 'circle_qipao5', COLOR_LIST.QIPAO, 15);126 drawCircle(data, 'circle_qipao6', COLOR_LIST.QIPAO, 10);127 drawCircle(data, 'circle_qipao7', COLOR_LIST.QIPAO, 16);128

129 drawText(320, 69);130 });131 }132

133 draw('dist_3');134

135

136 })(window, window);

六、代码 & 实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值