需求背景:
使用 DragonBones 在 Webview 中繪制骨骼動畫,并對當(dāng)前的骨骼頁面進(jìn)行圖層截取,實(shí)現(xiàn)保存本地和分享功能搀绣。
問題:
使用 DragonBones 制作骨骼動畫時(shí)遇到一個(gè)問題肝集,使用 WKWebView 加載骨骼動畫正常,再對 WKWebView 的父容器 view (控制器 view )進(jìn)行截圖是出現(xiàn)空白暮蹂。
解決思路及方案一:
通過資料查閱,發(fā)現(xiàn) WKWebView 在截圖時(shí)比較特殊,需要調(diào)用 UIView 的分類齐邦,也就是
- (nullable UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates NS_AVAILABLE_IOS(7_0);
進(jìn)行View圖層的快照獲取椎侠,推測和 WKWebView 的渲染原理相關(guān)。因?yàn)檎A鞒潭际峭ㄟ^ UIGraphics 去捕捉 UIView 的上下文來生成 UIImage 對象措拇,進(jìn)而分享或保存到本地我纪。
+ (UIImage *)getSharingImageWithView:(UIView *)originView {
UIImage *snapshotImage = nil;
UIGraphicsBeginImageContextWithOptions(originView.bounds.size, NO, [UIScreen mainScreen].scale);
[originView.layer renderInContext:UIGraphicsGetCurrentContext()];
snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshotImage;
}
對 WkWebView、TableView 等滾動視圖循環(huán)截屏可參考 TYSnapshotScroll丐吓。
當(dāng)然浅悉,例如 TYSnapshotScroll 提供的 WKWebView 截圖方式(snapshotViewAfterScreenUpdates)截取方式對類似 github、google 等首頁的截取非常完美券犁。
但是术健,在加載骨骼動畫時(shí)只有動畫背景,沒有任務(wù)形象粘衬。
解決思路及方案二:
根據(jù)從安卓和前端收集的信息來看:
- h5 骨骼動畫底層使用了 canvas 繪圖(一個(gè)類似于 iOS CoreGraphic 的庫荞估,專門負(fù)責(zé)繪制復(fù)雜圖形咳促。)
- JavaScript 使用 canvas 繪圖時(shí),會存在這樣的關(guān)系勘伺,直接上圖
- 上圖中最有價(jià)值的線索是跪腹,canvas 會調(diào)用 webGL 進(jìn)行渲染,同時(shí)會調(diào)用硬件加速功能
- 安卓端在手動關(guān)閉硬件加速后飞醉,該頁面截屏恢復(fù)正常冲茸。
然鵝,只有 Safari 中有對 WebGL 有控制權(quán)缅帘,WKWebView 并不能通過代碼關(guān)閉硬件加速轴术。
所以只能放棄使用 canvas 動態(tài)繪制的 webView 進(jìn)行圖像提取。
所以钦无,我們采取了采取了雙端結(jié)合的思路:
- 由 JavaScript 通過 canvas 輸出 base64 圖片字符串逗栽,以及人物背景圖片的URL
JavaScript生成圖片:
var fullQuality = canvas.toDataURL('image/jpeg', 1.0); // 參數(shù)二控制圖片質(zhì)量
// data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...9oADAMBAAIRAxEAPwD/AD/6AP/Z"
var mediumQuality = canvas.toDataURL('image/jpeg', 0.5);
var lowQuality = canvas.toDataURL('image/jpeg', 0.1);
Native 解析圖片:
NSData *decodedImageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:base64String]];
UIImage *decodedImage = [UIImage imageWithData:decodedImageData
scale:[UIScreen mainScreen].scale];
personImageView.image = decodedImage;
- 由 Native 對使用這些資源進(jìn)行布局渲染,并且控制截屏?xí)r用戶信息铃诬、二維碼等元素的展示祭陷,效果如圖:
總結(jié)
對于部分特殊控件的圖像處理可能要會出現(xiàn)位置的異常,需要對對應(yīng)的底層實(shí)現(xiàn)技術(shù)點(diǎn)進(jìn)行剖析趣席,倒推引起的原因。
參考:
HTML5 Canvas,WebGL,CSS Shaders,GLSL的曖昧關(guān)系
egret
dragonBone