如何快速的合成各种样式的图片

在某Q和某信中都有我们熟悉的公众号和结构化消息,例如

又或者这样:

这些图片都是固定的,每个用户看到的图片都是同一张。第一张,实在没有太多的点击欲望!第二张就还算凑合吧,不过哪来天天这么多福利图!

如果想让每个用户看到的消息有所不同,因人而异,我们需要依赖终端做相应的开发。

例如某某运动的消息:

这种方式就比固定图片好很多了,用户的点击欲望明显加强。非常好!除了开发周期慢一点之外。

呃,不妙,很快又要过阅兵节,然后是月饼节!老板想要做更炫酷的消息,怎么办?马上打电话给终端同学:“喂!喂?喂!3天能给我修改好模版吗?”。不过终端同学不是神,做得出来也发布不了。。。

那么,我们聪明的产品同学就想到了“动态合成图片”的高招,马上找到我们前后台开发。我们一碰面,又马上敲定可以搞起,问题就是怎么搞起了。

好啦,废话说完,该进入正题了。

消息的样式:

设计同学是毫不手软啊,真当这里是网页一样,各种设计各种字体各种效果各种进度条。

项目情况:

  • 100万活跃用户
  • 2小时内推送200万个消息

200万个消息也就是200万个图片,2小时内推送完成,也就是每秒大概300张图片。3ms一张图片?开什么玩笑?你以为每个服务器都有博尔特这么快吗!你要知道,这个图片并不小(630*350),要拼图,还要编码为JPG/PNG什么的。

挑战是存在的,需求是要做的,任务是要完成的。我们开始研究合成图的各种现成的方案(那些从零开始实现各种尖端算法的思路就算了),包括:

  • C++图形库;
  • 浏览器截图;
  • Flash。

什么?浏览器截图?什么?Flash?服务器生成图片,跟浏览器和Flash什么事?

别急,我们慢慢说明。

C++图形库:

后台同学哪个不是精通C++,所以我们的后台同学就开始研究各种C++方案。列出来一大堆:Boost.GIL、CImg、CxImage、FreeImage、Magick++(ImageMagick)、GDCM、ITK、OpenCV、VIGRA、VTK。各种高级术语,吓你一跳。

首先,尝试的是专业的Boost.GIL,但发现api羞涩难懂。后又转到街知巷闻的ImageMagick,很多重构同学都是用这个库做图片压缩。于是,后台同学浴血奋战,拼出了第一个效果:

,看来离目标效果不远了。虽然这给人感觉win10和win95的感觉,但要知道,win95升级4、5次就到win10了。

不过,悲剧的还不是这个丑,悲剧的是,合成一张jpg一共需要耗时300ms!

请允许我掐指一算,300ms一张,一秒3张,要达到一秒300张的目标,就需要100台机器。嗯,大老板这么有钱,应该不会介意的。

好吧,开个玩笑,后台同学彻底放弃了。

浏览器截图:

为什么要想浏览器截图?其实以前在项目中用过,只不过当时并没有这么高的速度要求。毕竟设计稿就非常适合用网页实现,如果浏览器截图的速度能达到要求,那么做这个动态图片的成本就很低了。

有很多linux命令行工具,可以对网页截图,原理是启动webkit渲染网页,然后截图。例如gnome-screenshot、wkhtmltoimage。

实际情况是让人沮丧的,截图随便需要1秒2秒的时间。

不过,这个也是能理解的,毕竟要启动webkit,网页要刷新,再截图,能不慢吗?

Flash:

笔者本身做Flash出身,所以对Flash生成图片情有独钟,既然如此,何不拿Flash测试一下呢?

经过测试,我们发现Flash不单能轻松的完美复现设计的效果,而且截图效率非常高,最终也选择了这个方案。

不过,要让Flash运行在linux服务器上,倒是要下一番功夫。

研究的内容包括:

  • Flash player or Air?
  • Flash和C++的通信?
  • 高效压缩图片?

#Flash player or Air?

player和air只是swf运行的两种形式而已,对速度不会有影响。研究这个目的是尝试实现原来的通信架构,因为Air模式才能在flash侧运行ServerSocket。如果Flash能运行ServerSocket,那么Flash就称为服务提供者,C++需要合成图的时候,只需要连接socket,传输参数,然后接收图片即可。

不过,Adobe于2011年宣布从air 2.7开始不再支持linux版本,所以否决了Air,还是继续使用Flash player。另外,要让flash正常运行起来,还需要安装xvfb服务。

#Flash和C++的通信?

为了保证高效的通信,避免每次截图都重启Flash player,我们设计了这样的通信机制:

C++控制Flash的生命周期,定期重启Flash。Flash启动后,马上链接C++提供的socket服务。连接成功后,C++给Flash分配任务,传输相应的用户数据;Flash接收数据后,拉取用户头像、生成图片并压缩为JPG,再以二进制形式在socket中回传给C++。回传完毕后,Flash保持socket连接,等待新的任务。

#高效压缩图片?

图片动态拼接完成后,需要压缩为png或者jpg,又或者更多其他格式。当然,在当前的软件环境来看,jpg和png是唯二的选择了。

我们做了很多测试,包括:

  • as3core压缩80%的jpg和无损png,也就是as3代码做编码运算
  • 改进版pngencoder:https://github.com/cameron314/PNGEncoder2
  • flascc(alchemy c++加速)压缩80%的jpg(as3_jpeg_wrapper)
  • png8和有损png24,使用的是blooddy(https://github.com/kenkozheng/blooddy),其中也有flascc加速。

大致的情况如下:

综合文件大小和压缩时间,我们暂时选择了flascc压缩的jpg。

但清晰度方面略有欠缺,80%质量的jpg在呈现文字时,边缘会略有模糊。不过这只在大屏机器上有细微的感觉。后续可能会考虑改为blooddy压缩的有损png24,虽然文件大小和耗时都比现有方案增加1倍,但图片要清晰一些。不得不赞扬一下blooddy的作者,俄罗斯人做软件要么就不做,要做就是很牛逼的。

有一个基础数据还没列出,就是Flash拼接生成画面的时间。这个倒是快的惊人,不算加载图片的时间,只需要8ms左右。

那么最终,Flash生成一张图的时间大概就是40ms。

最后,请再允许我掐指一算。默默的打开计算器。。。

40ms*2000000/1000 = 80000s = 22.2小时

那么如果同时有10台机器,就大概可以在2小时内发送完成了。虽然100台机器搞不到,10台机器还是有办法的

当然,实际情况还有图片传输的耗时(实际上这里更大,要传输到公众号平台),实际需要200ms一张图片,不过这些都是异步的,我们单机启动25个Flash进程,总体运行平滑。

时间: 2024-09-30 19:57:40

如何快速的合成各种样式的图片的相关文章

IIS发布,无法显示CSS样式和图片

在BS的项目中,完成之后,都需要发布自己的网站.这个时候就要安装IIS了. 我也是最近才打算使用IIS来进行发布的.刚把IIS安装上,就遇到了问题. 出现问题就想办法解决问题呗.遇到的问题和视频里面的类似,他也讲了一下是如何解决的.不过,他的只是不显示图片.而我的是 图片和CSS样式都显示.错误的原因:路径与发布不一致. 检查了一下自己的代码,路径写错?这也不至于全写错吧. 打开自己发布前的vs程序,执行一下:没问题.如果是路径错了,在vs程序中检查,也应该不显示才对? 既然程序没问题,发布也没

css Cursor:url()自定义鼠标指针样式为图片

css自定义鼠标指针样式为图片Cursor:url()的使用,今天在项目中,要用到自定义鼠标样式,格式: css:{cursor:url('绝对路径的图片(格式:cur,ico)'),-moz-zoom-out;}//FF下面 css:{cursor:url('绝对路径'),auto;}//IE,FF,chrome浏览器都可以 前面url是自定义鼠标格式,图像的绝对路径地址,后面的参数是css标准的cursor样式,(IE下面可以不需要) 图标的格式根据不同的浏览器来分:IE支持cur,ani,

php图文合成文字居中(png图片合成)

header('Content-type:text/html;charset=utf-8'); /** * png图文合成 by wangzhaobo * @param string $pic_path 图片目录 * @param array $text 文字 * @param array $font_file 路径 * @param array $font_size 文字大小 * @param array $font_pos_y 文字距离图片高度 * @return string 合成图片的名

css3实现单选、多选按钮改变其原生样式用图片代替

最近才开始写博客,所以把前几个月做项目时遇到的问题整理一下写出来,众所周知,表单中的一写元素原生样式不是很好看,项目中用到的时候需要优化,今天我就写一下单选按钮很多选按钮的样式的优化,首先自己要做出按钮选中之前的图片和按钮选中之后的图片.然后就是代码了.直接上代码:(代码比较多,这是我之前在做项目时样式都搬过来了,样式什么都是可以自己写的.) HTML代码结构如下: 1 <div class="radio" > 2 <label> 3 <input typ

怎样可以快速将pdf文件转换为jpg图片

有些PDF文件中会有一些图像内容,在使用需要使用这些图片的时候需要把这些内容转为jpg格式的图片,将文档转成图片看上去不是难事,但是想要快速的把文档转换成统一规格的jpg图片也是需要方法的. 要将PDF文件转成JPG图片,使用截图的方式对于一些页面较多的文档显示是不可取的.除此外还有一些简便的方法可使PDF文件转换成为JPG图片. 直接通过在线转换,首先进入在PDF在线转换器app.xunjiepdf.com.然后找到“PDF转成图片”这个转换类型,点击进入操作. 首先选择文件,把要转换的文件添

如何用PS快速做出3D按钮效果的图片

1 先建立一个透明图层 2:再创建一个矩形 3:选用过喷样式 4: 双击图层并应用蓝色,记得这里应该复制下颜色的16进制值. 效果如图所示 取消光泽选项,大功告成! 最终效果如图所示,将其保存为PNG格式的图片即可使用. 通过调节如下图所示的大小,可以制作不同深浅的按钮 效果图如下: 如果要制作圆形按钮,那么自定义形状时选择圆形即可. 这真是太简单了!

jQuery之修改li下样式和图片

<script type="text/javascript"> $(document).ready(function(){ $('li').click(function(){ /* 将所有li样式替换为cz(默认样式) */ $('li').removeClass('selected-cz'); $('li').addClass('cz'); /* 将选中的li样式更改为selected-cz */ $(this).removeClass('cz'); $(this).ad

webpack4.0(四) --css样式及图片打包(style-loader,css-loader)

一.CSS样式打包 1. loader简介 由于Webpack打包入口目前只配置了一个index.js文件,那么其他需要被打包的文件都必须通过模块化方式引入该文件才行,而默认情况下,引入的文件必须是js文件(如项目里添加的index.js). 那么其他文件类型该如何进行打包呢?这时我们就要用到webpack中所提供的各种loader,它就是专门用于处理除JS文件之外的其他格式文件的编译.提取.合并.打包等. 其中CSS文件的打包需要用到style-loader和css-loader这两个依赖包,

怎样将图片1、图片2合成一张新的图片

dispatch_group_notify(group, queue, ^{ // 1.开启新的图形上下文 UIGraphicsBeginImageContext(CGSizeMake(100, 100)); // 2.绘制图片 [self.image1 drawInRect:CGRectMake(0, 0, 50, 100)]; [self.image2 drawInRect:CGRectMake(50, 0, 50, 100)]; // 3.取得上下文中的图片 UIImage *image