需求背景:
使用 DragonBones 在 Webview 中繪制骨骼動畫,并對當前的骨骼頁面進行圖層截取,實現保存本地和分享功能。
問題:
使用 DragonBones 制作骨骼動畫時遇到一個問題,使用 WKWebView 加載骨骼動畫正常,再對 WKWebView 的父容器 view (控制器 view )進行截圖是出現空白。
解決思路及方案一:
通過資料查閱,發現 WKWebView 在截圖時比較特殊,需要調用 UIView 的分類,也就是
- (nullable UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates NS_AVAILABLE_IOS(7_0);
進行View圖層的快照獲取,推測和 WKWebView 的渲染原理相關。因為正常流程都是通過 UIGraphics 去捕捉 UIView 的上下文來生成 UIImage 對象,進而分享或保存到本地。
+ (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 等滾動視圖循環截屏可參考 TYSnapshotScroll。
當然,例如 TYSnapshotScroll 提供的 WKWebView 截圖方式(snapshotViewAfterScreenUpdates)截取方式對類似 github、google 等首頁的截取非常完美。
但是,在加載骨骼動畫時只有動畫背景,沒有任務形象。
解決思路及方案二:
根據從安卓和前端收集的信息來看:
- h5 骨骼動畫底層使用了 canvas 繪圖(一個類似于 iOS CoreGraphic 的庫,專門負責繪制復雜圖形。)
- JavaScript 使用 canvas 繪圖時,會存在這樣的關系,直接上圖
canvas 的七大姑八大姨
- 上圖中最有價值的線索是,canvas 會調用 webGL 進行渲染,同時會調用硬件加速功能
- 安卓端在手動關閉硬件加速后,該頁面截屏恢復正常。
然鵝,只有 Safari 中有對 WebGL 有控制權,WKWebView 并不能通過代碼關閉硬件加速。
所以只能放棄使用 canvas 動態繪制的 webView 進行圖像提取。
所以,我們采取了采取了雙端結合的思路:
- 由 JavaScript 通過 canvas 輸出 base64 圖片字符串,以及人物背景圖片的URL
JavaScript生成圖片:
var fullQuality = canvas.toDataURL('image/jpeg', 1.0); // 參數二控制圖片質量
// 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 對使用這些資源進行布局渲染,并且控制截屏時用戶信息、二維碼等元素的展示,效果如圖:
骨骼動畫截屏
總結
對于部分特殊控件的圖像處理可能要會出現位置的異常,需要對對應的底層實現技術點進行剖析,倒推引起的原因。