在某Q和某信中都有咱們熟悉的公衆號和結構化消息,例如html
又或者這樣:linux
這些圖片都是固定的,每一個用戶看到的圖片都是同一張。第一張,實在沒有太多的點擊慾望!第二張就還算湊合吧,不過哪來每天這麼多福利圖!c++
若是想讓每一個用戶看到的消息有所不一樣,因人而異,咱們須要依賴終端作相應的開發。git
例如某某運動的消息:github
這種方式就比固定圖片好不少了,用戶的點擊慾望明顯增強。很是好!除了開發週期慢一點以外。web
呃,不妙,很快又要過閱兵節,而後是月餅節!老闆想要作更炫酷的消息,怎麼辦?立刻打電話給終端同窗:「喂!喂?喂!3天能給我修改好模版嗎?」。不過終端同窗不是神,作得出來也發佈不了。。。算法
那麼,咱們聰明的產品同窗就想到了「動態合成圖片」的高招,立刻找到咱們先後臺開發。咱們一碰面,又立刻敲定能夠搞起,問題就是怎麼搞起了。api
好啦,廢話說完,該進入正題了。瀏覽器
消息的樣式:服務器
設計同窗是絕不手軟啊,真當這裏是網頁同樣,各類設計各類字體各類效果各類進度條。
項目狀況:
200萬個消息也就是200萬個圖片,2小時內推送完成,也就是每秒大概300張圖片。3ms一張圖片?開什麼玩笑?你覺得每一個服務器都有博爾特這麼快嗎!你要知道,這個圖片並不小(630*350),要拼圖,還要編碼爲JPG/PNG什麼的。
挑戰是存在的,需求是要作的,任務是要完成的。咱們開始研究合成圖的各類現成的方案(那些從零開始實現各類尖端算法的思路就算了),包括:
什麼?瀏覽器截圖?什麼?Flash?服務器生成圖片,跟瀏覽器和Flash什麼事?
別急,咱們慢慢說明。
C++圖形庫:
後臺同窗哪一個不是精通C++,因此咱們的後臺同窗就開始研究各類C++方案。列出來一大堆:Boost.GIL、CImg、CxImage、FreeImage、Magick++(ImageMagick)、GDCM、ITK、OpenCV、VIGRA、VTK。各類高級術語,嚇你一跳。
首先,嘗試的是專業的Boost.GIL,但發現api羞澀難懂。後又轉到街知巷聞的ImageMagick,不少重構同窗都是用這個庫作圖片壓縮。因而,後臺同窗浴血奮戰,拼出了第一個效果:
嗯,看來離目標效果不遠了。雖然這給人感受win10和win95的感受,但要知道,win95升級四、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?
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是惟二的選擇了。
咱們作了不少測試,包括:
大體的狀況以下:
綜合文件大小和壓縮時間,咱們暫時選擇了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進程,整體運行平滑。