#程序员也要秀恩爱 [TOC] 好几个月没更新博客了,眼看就快过年了,我这段时间都去干嘛了呢? 其实也没干嘛,就是趁着国庆期间结了个婚,换了个工作…… 要说婚后体会的话,个人感觉还是挺棒的~ 既然人生进入另一个阶段了,博客的第一篇还是要围绕这个主题的,那就是,程序员有时候也是不得不搞点讨好妹纸的事情啊…… 然而,技术实现的本身更多注意力在业务逻辑上,而不是漂不漂亮……所以,程序员的很多秀恩爱,往往特别有硬感……而在这其中像素艺术和ASCII码艺术是其中两个脱颖而出的形式,可谓是层出不穷……比如说我个人就比较喜欢这两种形式…… ## Excel是伪装成办公软件的画图工具 近几年来,关于用Excel画图的新闻轶事已经屡见不鲜了。为啥Excel画图这么受欢迎呢? - 首先,对于大部分的电脑来说都是自带的,不用专门下载个工具。比较出名的用Excel画图的日本老人就是因为计算机自带的原因,当然,真正的原因是穷,买不起正版的专业画图软件…… - 其次,用它画图真的很好用。Excel自带的表格虚线为画图提供了天然的辅助线,还可以控制行高列宽来辅助对齐,这就是用Excel而不用word的原因。而其自带的矢量作图工具堪比PhotoShop的钢笔工具,对于简单的矢量图绘制来说,容易上手又好控制。好多人在面对画图的问题时,都会纠结要不要买个数位板。而用Excel画图完全不担心,矢量绘图是用鼠标拖动曲线的操纵柄来完成曲线的修改编辑的,真正为鼠标准备的作图方式,不关数位板的事; - 再次,用Excel作图可以装B。不要觉得这条没什么用,这确实是很大一部分人非要把Excel搞成一个画图工具的真正原因。把一个非专业的作图工具搞成一个比专业作图工具更炫酷的东西,难道不吸引眼球么? 能说这么多是因为我也玩过Excel画图,然而我绘画水平尚浅,只能临摹,并不能独立构图,下面就是我在Excel上临摹的QQ图标(我真的没收腾讯一分钱)。 ![用Excel绘制QQ图标](Excel_QQ.jpg "用Excel绘制QQ图标") 说起来并没有那么难,简单介绍一下,就是插入图片,放到最底下一层,然后用鼠标拖动曲线的操纵柄,顺着图画的边缘进行操作,精细处可以放大再操作,掌握好角点和平滑点的转换,然后选择填充和线条颜色粗度,注意好层次遮挡,巧妙的利用组合与解除组合,善于使用各种渐变来体现效果,就行了。听上去很玄乎,自己试试就会发现,没那么难…… 然而说了这么多,这次要说的不是这个……因为矢量作图这些事,都是我四五年前玩的东西了,那个QQ图标是我13年底无聊时临摹的……这次我们来换个方式…… 除了矢量图,自然是位图,用Excel绘制位图也是一种独特的体验,先把行高和列宽控制到想要的大小,然后,按照一格是一个像素来进行染色,染时间长了,就感觉自己在玩涂鸦游戏了~ 不管是平涂还是厚涂的画师,一般都是先打辅助线,画草稿,然后才开始涂色。而excel也可以基本上做到这一切,可以先用曲线把轮廓勾勒一下,然后再选中相应的单元格设置背景色,最终完成一个位图图形。 使用这种位图作图手法所做的图的好处是颜色层次多,较为灵活,不好处就是单元格太大像素感会很重,单元格小了,操作又过于复杂,特别是对于边缘处理上,有点反复而机械,尽管可以通过双击格式刷的方式进行批量操作,也可以使用shift、ctrl进行方块区域的批量选择,但是并没有更好的方法。 或许有人能利用Excel的VBA扩展将Excel整成效率更高的位图作图工具,还是挺期待的(可以结合后面提到的图元生成尝试一下)……VBA使得Excel无所不能…… 介绍完Excel的矢量图作图方法和位图作图方法之后,然而之后要说的事,跟这些都没有半毛钱关系……因为……我绘画水平拿不出门去啊…… 既然矢量图能有一个跟着描的方式可以用来装B,位图一定也有一个方法吧…… 这个其实就简单的多了……因为我们常见的图片都是位图,要搞成矢量图,一般情况下还是手工描最靠谱,当前的大部分转矢量图的方案可能并不太好使……但是位图就不一样了…… 要转成表格也是分分钟的事情……我前段时间研究验证码的时候,搞luaGD库,想想稍微写写还是能够完成这种操作的……于是,基本思路就诞生了: 首先,通过luaGD库将位图转成html的表格,然后,复制,粘贴到Excel中稍微编辑一下,改一改行高列宽,然后,就可以冒充是在Excel里画的了……(画外音:我从未见过如此厚颜无耻之人) 这种方法可以提供一个很好的网格图样,对于十字绣之类的图样参考也是不错的……另外,我发现早期的Excel背景色只有256种颜色可选,就像是十字绣也是固定的那么几种颜色,并没有那么多的颜色层次…… 于是,我还在里面提供了相应的参数来控制到相近的可选颜色上……然后下面就是代码和使用说明了…… ```lua -- File: img2table.lua require("gd"); if #arg<1 or #arg>4 then print("用法:"..arg[0].." <图片路径> [颜色数目,默认32] [是否抖动{1/true为是,其他默认false}] [单元格尺寸,单位:像素,默认:2]"); return false; end local colors = nil; if #arg >=2 then colors = tonumber(arg[2]); end if colors == nil then colors = 32; end local dither = nil; if #arg >=3 then dither = (arg[3]:upper() == "TRUE" or arg[3]=="1"); end if dither == nil then dither = false; end local cellSize = nil; if #arg >=4 then cellSize = tonumber(arg[4]); end if cellSize == nil then cellSize = 2; end --[[ function file_exists(path) local file = io.open(path, "rb") if file then file:close() end return file ~= nil end if not file_exists(arg[1]) then print("找不到文件【"..arg[1].."】"); return false; end --]] local fp = io.open(arg[1], "rb"); if fp == nil then print("读取文件失败【"..arg[1].."】"); return false; end local fstr = fp:read("*a"); fp:close(); fp = nil; local tryFuncs={ png = gd.createFromPngStr, jpg = gd.createFromJpegStr, gif = gd.createFromGifStr, xbm = gd.createFromXbmStr, xpm = gd.createFromXpmStr, gd = gd.createFromGdStr, gd2 = gd.createFromGd2Str }; local img = nil; for ft,func in pairs(tryFuncs) do img = func(fstr); if img ~= nil then print("文件类型【"..ft.."】"); break; end end if img == nil then print("无法识别的文件格式!"); return false; end local ox, oy = img:sizeXY(); print("原始图片尺寸:"..ox..","..oy); local x, y = 256, math.floor(oy*256/ox); print("输出表格尺寸:"..x..","..y); local im = gd.createPalette(x, y); img = img:createPaletteFromTrueColor(dither, colors); im:paletteCopy(img); --im:copyResized(img, 0, 0, 0, 0, x, y, ox, oy); im:copyResampled(img, 0, 0, 0, 0, x, y, ox, oy); img = nil; local _,_,filePath,fileName = arg[1]:find('^(.*)([^\\/]+)[\\.][^.]+$'); fileName = filePath..fileName..".html"; print("输出文件名【"..fileName.."】"); fp = io.open(fileName, "w"); fp:write([[ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <meta http-equiv="Content-Type" content="text/html; charset=GBK" /> <meta name ="Keywords" content="生成图片表格" /> <meta name="Author" content="yimengqiannian/jingchangjiang1988@163.com"> <meta name="Date" content="]]..os.date()..[[" /> <meta name="Generator" content="lua program" /> <meta name="Description" content="生成图片表格" /> <meta name="Copyright" content="Copyleft" /> <meta name="Robots" content="all" /> <title>图片表格【]]..arg[1]..[[】</title> <style> td{ width:]]..cellSize..[[px; height:]]..cellSize..[[px; } table{ border-collapse:collapse; /*border: 1px solid #000;*/ } </style> <body> <h1><center>图片表格【]]..arg[1]..[[】</center></h1> <table align="center" border="0" cellspacing="0" cellpadding="0"> ]]); for j = 0,y-1 do fp:write("<tr>"); for i = 0,x-1 do local c = im:getPixel(i,j); fp:write("<td bgcolor=\""); fp:write(("#%02X%02X%02X"):format(im:red(c),im:green(c),im:blue(c))); fp:write("\"></td>"); end fp:write("</tr>\n"); end fp:write([[ </table> </body> </html> ]]); fp:close(); fp = nil; print("输出完成~"); im = nil; ``` 代码不多,很容易理解,就不过多解释了,然后就是使用说明: ``` 将图片转换为带颜色的表格形式。 命令行方式调用: 用法:img2table.exe <图片路径> [颜色数目,默认32] [是否抖动{1/true为是,其他默认false}] [单元格尺寸,单位:像素,默认:2] 如: img2table.exe yuxia.jpg 100 1 3 即将yuxia.jpg转换为颜色数目为100,含有抖动,每个单元格边长3像素的html表格 拖拽方式调用: 直接将图片文件拖拽到img2table.exe图标上,此时会在图片所在目录生成html文件,此时默认32种颜色,不使用抖动,单元格默认2像素 生成的html文件用浏览器打开后可以直接选中复制粘贴到excel中,全选,设置行高和列宽即可。 生成的表格统一默认宽度为256(程序内置,无法通过命令行控制)。 脚本文件源码以及绑定相关文件在src目录中,bind.bat为将lua脚本绑定到exe上时用的脚本。 ``` 生成的表格统一为256的原因是考虑到性能问题……大家感兴趣可以自己改…… 然后就是生成效果的示意图了: ![生成html图片表格示意图](html.png "生成html图片表格示意图") 复制粘贴到Excel里是这样的: ![复制粘贴到Excel后的示意图](excel.png "复制粘贴到Excel后的示意图") 然后就可以发给妹纸说,哎呀,我花了一上午的功夫搞出来的,怎么样?(其实并没有说谎,写程序用了一上午呀~) 这样还可以录视频到B站,冒充技术宅~~ 最后,给一个[下载链接](https://pan.baidu.com/s/1dGSQ2tj "下载链接")。 ## 不要低估OpenWRT的杀伤力 我个人挺喜欢ASCII艺术和像素艺术的,这个不必多说,从很久之前的写过一个[字模获取](http://1157.huaying1988.com/getZM.html "字模获取")。 就说前两天吧,想起来,字模有了,当年不是说要搞的图模的么?图形比文字更有表现力和张力啊…… 废了一番功夫,写了个图模的,可以[点击看效果](http://1157.huaying1988.com/pix2num.html "图模转换工具")。 其实本来是想把之前研究的[2D简单图元生成](http://1157.huaying1988.com/2DLearn/paint.html "2D简单图元生成")加进去的,但是想想,先用这个图模讨好一下妹纸吧…… 既然图模有了,得选择一个语言来把它展示出来吧…… Windows脚本技术(WSH—— 一般使用VBScript和JScript,文件缩略名为*.wsf)是一个较好的可选技术,因为windows自带,双击就能运行。 然而我没有选……既然是这种比较有原始感的东西,自然要用看上去比较原始的表现形式……我选择批处理脚本……黑窗口一蹦出来,那种原始感就油然而生…… 代码很简单,没几行: ```bat @echo off & setlocal ENABLEDELAYEDEXPANSION & title I Love You! & color FC set array=0,7196,15934,32639,32767,32767,32767,16382,8188,4088,2032,992,448,128,0,37735,38898,38898,37858,37314,24711,0 for %%i in (%array%) do ( set str= for /L %%j in (0,1,15) do ( set /A test="%%i&(1<<%%j)" if /i !test! GTR 0 (set str=!str!■) else (set str=!str! )  ) echo. !str! ) pause color 07 & title cmd & setlocal DISABLEDELAYEDEXPANSION & @echo on ``` 展示效果是这样的: ![小心心效果图](iloveu.png "小心心效果图") 然而,这样就行了么?当然不可以…… 这种花招玩的太多可就不新鲜了……得玩点更具有杀伤力的东西…… 于是我把注意力关注到了我家的路由器上了……我家的路由器是被我刷了OpenWRT的……早就想在上面搞事情了,但是一直都没搞……为啥?因为懒…… 我的想法很简单,用路由器劫持HTTP协议报文,然后插入我想要执行的脚本,这样就能实现我想要的HTTP轰炸! 只要打开网页,就会出现一个我想展示的图案,然后3秒钟后消失……这招当然是跟移动联通之类的运营商广告学的…… 这样的轰炸应该对妹纸比较有效果~ 首先得选择合适的OpenWRT插件来实现想要的效果……选来选去,最后用的是privoxy…… privoxy是个代理插件,它可以在代理过程中实现一些过滤,本来是用来过滤广告的……但是,我们要用它来插入广告…… 首先是安装privoxy,这个不用多说,可以直接在LuCI界面操作,在线下载安装…… 然后就是配置privoxy。我之前的时候,照着网上的配置来,结果总是不生效……经过我的仔细研究才明白过来……我安装的这个privoxy所使用的配置是通过config配置生成的,并不是一个静态配置,真正的配置文件是/etc/config/privoxy 我的/etc/config/privoxy是这么配的: ```conf config privoxy 'privoxy' option confdir '/etc/privoxy' option logdir '/var/log' option logfile 'privoxy.log' list filterfile 'default.filter' list filterfile 'user.filter' list actionsfile 'match-all.action' list actionsfile 'default.action' list actionsfile 'user.action' # list listen_address '127.0.0.1:8118' # list listen_address '192.168.1.1:8118' list listen_address '0.0.0.0:8118' option toggle '1' option enable_remote_toggle '1' option enable_remote_http_toggle '0' option enable_edit_actions '1' option enforce_blocks '0' option buffer_limit '4096' option forwarded_connect_retries '0' option accept_intercepted_requests '1' option allow_cgi_request_crunching '0' option split_large_forms '0' option keep_alive_timeout '300' option socket_timeout '300' # list permit_access '192.168.1.0/24' list permit_access '0.0.0.0/0' option debug_1 '0' option debug_512 '1' option debug_1024 '0' option debug_4096 '1' option debug_8192 '1' ``` 然后就是过滤器的配置,不过在这之前要干一件事……那就是,我得把想要植入的脚本写出来,需求已经很明确了,直接写就行了…… ```JavaScript (function(){ if(window.top == window){ var zm = [0x0000, 0x1C1C, 0x3E3E, 0x7F7F, 0x7FFF, 0x7FFF, 0x7FFF, 0x3FFE, 0x1FFC, 0x0FF8, 0x07F0, 0x03E0, 0x01C0, 0x0080, 0x0000, 0x9367, 0x97F2, 0x97F2, 0x93E2, 0x91C2, 0x6087, 0x0000]; var fontSize = 14; var tp = parseInt(window.screen.availHeight/2)-fontSize*16; var lft = parseInt(window.screen.availWidth/2)-fontSize*zm.length/2; var strArray =[]; for(var i=0;i<zm.length;i++){ for(var j=0;j<16;j++){ if(zm[i]&1){ strArray[strArray.length]="▇"; }else{ strArray[strArray.length]=" "; } zm[i] >>= 1; } strArray[strArray.length]="<br />"; } var div = document.createElement("div"); div.innerHTML = strArray.join(""); div.setAttribute("style","font-size:"+fontSize+"px;line-height:"+fontSize+"px;font-family:Consolas, Monaco, monospace;background-color:#FFF;color:red;position: absolute;left:"+lft+"px;top:"+tp+"px;"); document.body.appendChild(div); setTimeout(function(){document.body.removeChild(div);},3000); } })(); ``` 这段代码没啥好说的,就是上边那个批处理脚本改成JS版了,然后再加上显示的一些样式,还有3秒钟后移除的操作。 然后把这段代码上传到自己的服务器上,到时候直接外部引入就行了,我把它[放到了这儿](http://1157.huaying1988.com/love.js "要执行的脚本")。 然后开始过滤器的配置。 首先是/etc/privoxy/user.filter文件的末尾添加这么几行,创建myLoveScript过滤器在body标签结束的前面添上自己要注入的脚本: ``` FILTER: myLoveScript s|</body>|<script type="text/javascript" src="http://1157.huaying1988.com/love.js" charset="UTF-8"></script>$0| ``` 然后是应用过滤器,在/etc/privoxy/user.action文件的末尾添加这么几行,对所有的请求都添加该过滤器: ``` {+filter{myLoveScript}} .* ``` 然后是设置privoxy自动启动,重启privoxy: ```shell # /etc/init.d/privoxy enable # /etc/init.d/privoxy restart ``` 之后,还剩最后一步,通过iptables将所有的请求都转到privoxy代理上: ```shell iptables -t nat -A PREROUTING -s 0.0.0.0/0.0.0.0 -p tcp --dport 80 -j REDIRECT --to-ports 8118 ``` 再随便打开个网页,不管是手机还是计算机,都会显示3秒钟的小心心图案了…… ![OpenWRT注入示意图](boom.png "OpenWRT注入示意图") 然而有一个问题,就是……只能注入http协议的连接,不能注入https的连接…… 要注入https还是有一定难度的,但也不是不可以……从这点小事上也可以看出https安全性确实比http高…… 然而现在http的网站越来越少了,特别是较大的一些网站……所以,总有一天,这个方法会完全不奏效了…… 当然,一开始在路由器上搞上这个东西的时候,妹纸是很开心的……然而确实能体会到,打开网页有些变慢了…… 后来的结果是:显摆了一天之后,我就把它去了…… ## 最终却败给了俄罗斯方块 我是很喜欢闲的没事实现一些小游戏的,比如说[贪吃蛇](http://1157.huaying1988.com/tcs.html "贪吃蛇")、[彩球滑梯](http://1157.huaying1988.com/cqht.html "彩球滑梯")、[打字游戏](http://1157.huaying1988.com/typeGame.html "打字游戏")、[记忆测试](http://1157.huaying1988.com/memoryTest.html "记忆测试")还有想当年跟同事一起合作的[扫雷](http://1157.huaying1988.com/hzsl.html "扫雷")。 还有很多,不再一一列举了……然而事实上我从初中开始就有一个想法,就是实现个俄罗斯方块游戏……之前的时候没去实现,是因为能力不够……确实实现不了…… 而后来没去实现,那纯粹是因为懒……这不是前几天研究像素画么……就又想起来了…… 想法是,整个俄罗斯方块所有的展示都用像素画的形式来完成,是不是感觉比较有时代感呢? 于是,说干就干……最终,实现了[一个比较粗糙的俄罗斯方块](http://1157.huaying1988.com/tetris.html "刚实现的一个比较粗糙的俄罗斯方块")……我就不在此处贴源码了…… 操作很简单:A-左、D-右、S-加速落、W/J-顺时针转、K-逆时针转、空格-落到底、P-暂停(注:暂停期间仍然会计时) 试了试,感觉应该没太多的bug,就发给妹纸玩了……顺带还发给她了我打出来的最高分的效果图: ![我打出的最高分效果图](highScore.png "我打出的最高分效果图") 结果,妹纸不愿意了,非要超过我的分数不可……于是一有空就玩……几天过去了都没再理我…… 一直到现在,还是一有功夫就玩它,想要超过我……:weary:


花楹2018-1-29 19:51:50 说:
回复 @羽夏 : 可惜文章的结局好悲催……(T_T)
羽夏2018-1-29 19:39:02 说:
这一波秀的有水平~hen专业呀~
发表评论

必填,公开,这样称呼起来方便~

必填,不会被公开,不必担心~

http://

非必填,公开,目的是方便增进友好访问~

必填,请输入下方图片中的字母或数字,以证明你是人类

看不清楚
必填,最好不要超过500个字符
     ↑返回顶端↑