白夜追兇 :手 Q 圖片的顯示和發送邏輯

歡迎大家前往騰訊雲社區,獲取更多騰訊海量技術實踐乾貨哦~

作者:陳舜堯

導語: 「這張圖片在快捷發圖欄背景是黑色的,為啥發到AIO(會話窗口)里背景就變成白的了?」 通過一個bug單,對黑白背景問題跟進的過程中發現了手q中很多奇怪的表現。一層層看代碼,整理總結了手q中圖片的顯示和發送邏輯,以及對透明通道圖片的特殊處理。

一、黑背景?白背景?

這張圖片在快捷發圖欄背景是黑色的,發到AIO里背景就變成白的了。拿到問題,分析有兩種可能原因:展示view的背景色不一致;選中的png圖片的透明通道在AIO和快捷發圖欄兩個不同的場景下過濾規則不一致。

很容易就能發現兩個場景處理圖片的不同:快捷發圖欄將png圖片獲取為bitmap,再壓縮成jpeg,這個過程直接忽略了透明通道,android默認處理的結果就是一張黑色背景的jpeg。快捷發圖欄所有圖片的位元組流持久化到同一個文件里,這樣做的目的是下次從本地載入多張圖片時,會共用同一個文件IO,提高載入效率;

AIO中的縮略圖也是由原圖壓縮成jpeg,在處理的代碼中,我發現了人為加白色背景的邏輯,原來這都是產品的策略,可能考慮到AIO中png圖片黑色背景視覺上不太美觀,所以進行了特殊處理。然而快捷發圖欄和AIO中視覺上沒做到統一,有道是 產品拍頭一時爽,開發解bug火葬場

二、都是png,怎麼有黑又有白!

既然問題找到了,美滋滋的準備加個雞腿,然而事情並沒有那麼簡單!回歸問題的時候我用了另外一張png圖片測試,咦,怎麼這張圖片在AIO中背景是黑色的?

有兩個懷疑方向:1、png壓縮成jpeg的過程,丟失透明通道導致AIO中這張圖片為黑色背景;2、有沒有可能是在canvas上繪製白色背景失敗導致的該問題?

先從第一個方向分析,通過BitmapFactory.decode把png輸出為bitmap,再把白底、bitmap依次繪到canvas上,期間旋轉信息的處理、對長圖的特殊處理、subSample這裡就不展開了。這裡懷疑png輸出為bitmap時,透明通道丟失。

我們知道ARGB指的是一種色彩模式,裡面A代表Alpha,R表示red,G表示green,B表示blue,其實所有的可見色都是右紅綠藍組成的,所以紅綠藍又稱為三原色,每個原色都存儲著所表示顏色的信息值,Bitmap.Option中config的值有下面幾種,ALPHA_8 代表8位Alpha點陣圖 ,ARGB_4444 代表16位ARGB點陣圖 ,ARGB_8888 代表32位ARGB點陣圖 ,RGB_565 代表16位RGB點陣圖。有沒有可能是png輸出為bitmap的過程中,有奇葩的策略調整config的值導致ALPHA通道遺失?於是一步步斷點跟蹤這塊的代碼,很遺憾沒發現異常。

再看看第二個方向,我們review下加白色背景的代碼(見上圖),Paint設置了Xfermode。PorterDuff.Mode能設置canvas繪圖時不同圖層的混合方式,下圖展示了不同的混合方式。我們處理是將圖片bitmap疊加到白色背景上,這裡SRC_OVER看上去也沒問題。。。

啪啪啪打臉,看來不是懷疑的兩個方向出了問題。於是病急亂投醫把鍋甩給了圖片。。。。。

「會不會是png格式的問題,png某個參數導致轉化過程中bitmap背景不同????」

在查閱資料、用工具分析對比了兩張png圖片的結構,欣喜得發現問題跟png格式並沒有半毛錢關係。冷靜下來,還是用老辦法,一步一步跟代碼!!!!

遊戲圖壓縮後P2大於P1(是的你沒看錯,壓縮後圖片反而大,壓縮步驟取bitmap,再繪製,最後質量壓縮成jpeg),所以是拿原始圖片當作大圖P3去生成縮略圖P4,原始圖片有透明通道,所以對應的縮略圖能加上白色背景;骰子圖片壓縮後發現比原圖小,所以用壓縮圖P2當作大圖P3去生成縮略圖P4。P2是質量壓縮png生成的jpeg,已經丟失透明通道,是一張黑色背景的圖。即使在P4加上白色背景也被上層圖層覆蓋,我們看到的就是黑色骰子縮略圖。

我之前分析的過程中忽略了壓縮原始圖片生成P2這一步。一葉障目,理清了思路,問題就顯而易見了!

三、黑白分明,搞清楚所有情況下的表現

既然理清了流程,那就把所有情況下的表現分析下吧。我們看看勾選原圖下的表現。

這裡很好理解,骰子圖勾選原圖後,是把原始圖片生成縮略圖P4,原始圖有透明通道,所以生成的縮略圖也有白色背景。

如果是PC發送PNG圖片,客戶端去接收消息下載圖片呢?PC端發送圖片不存在是否勾選原圖的概念,也不存在壓縮的概念(耿直boy)。客戶端接收方會去下載PC端發送的圖片P5和架平生成的縮略圖P7。

四、黑白閃變是什麼鬼!

這時我在回歸過程中又發現了一起不尋常的現象。客戶端發送遊戲圖後,接收端收到圖片,在AIO中的縮略圖會有一個由黑變白的過程。呵呵,兵來將擋,bug來我解。又滾去熟悉了下接收端的邏輯。

發送的這張遊戲圖是由透明通道的,架平並沒有為有透明通道的圖片添加白色背景的策略,所以接收端下載的是一張黑色背景的架平縮略圖。

這裡要提到手q的預下載策略。用戶可能會去點開大圖,如果點擊時再去下載,轉菊花的過程體驗很差,所以手q會綜合網路情況、當前已用流量等維度去判斷是否需要提前幫用戶下載大圖。圖中圖片消息命中了預下載策略,手q幫用戶提前下載好了大圖。

這時候問了,大圖明明是黑色背景,為什麼AIO中會閃變成白色?哈哈哈,這裡又是手q人性化的一點,由於下載好了大圖,為了讓用戶在AIO中可以直接可以看到比較清晰的縮略圖,手q不信任架平生成的縮略圖,用已經下載的大圖在本地生成了相對高清的縮略圖。

而下載的大圖是有透明通道的png,根據前面已經提到的產品策略,我們會給本地生成的縮略圖加上白色背景,所以出現了閃變~

五、總結

全文告一段落,在跟進問題的過程中,又完整的走了一遍手Q的圖片發送流程。

除了提高對業務的熟悉程度之外,不禁感慨,前輩們為圖片發送展示流程做了數不清的優化項,前人栽樹後人乘涼,由衷的欽佩!

閱讀推薦

一站式滿足電商節雲計算需求的秘訣

Web 前端性能優化 : 如何有效提升靜態文件的載入速度

使用 Skeleton Screen 提升用戶感知體驗

此文已由作者授權騰訊雲技術社區發布,轉載請註明文章出處

原文鏈接:cloud.tencent.com/commu


推薦閱讀:

TAG:Android | 圖片處理 | 前端開發 |