生成圖片長微博遇到的坑

公司的App生成圖片長微博的功能已經(jīng)有一段時(shí)間,在開發(fā)時(shí)遇到過截屏出現(xiàn)黑色的問題.之前我以為是iOS7和7以上系統(tǒng)的問題,代碼是這樣寫的.

+ (UIImage*)snapshot {

UIViewController *topViewController = [UIViewController topViewController];

UIGraphicsBeginImageContextWithOptions(topViewController.view.bounds.size,YES,2.0f);

if([[[UIDevice currentDevice]systemVersion]floatValue] >=8.0) {

[topViewController.view.layerrenderInContext:UIGraphicsGetCurrentContext()];

} else {

[topViewController.viewdrawViewHierarchyInRect:topViewController.view.boundsafterScreenUpdates:YES];

}

UIImage*finalImage =UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

returnfinalImage;

}

判斷設(shè)備調(diào)用不同的方法來實(shí)現(xiàn).最近運(yùn)營的同事反饋出現(xiàn)了長圖中部分內(nèi)容空白的問題,后來在解決的過程中,之前的思考與解決方法有問題.下面我就說一下是如何解決的.

普通的截屏只要得到當(dāng)前ViewController.view 就可以進(jìn)行截屏.

順便提醒一下iOS 7上UIView上提供了drawViewHierarchyInRect:afterScreenUpdates:來截圖,速度比renderInContext:快15倍。

以騰訊新聞為例,每篇文章內(nèi)容長度不同,如果想生成長圖必須要把超過屏幕內(nèi)容也截出來.UICollectionView繼承UIScrollView,通過調(diào)整ContentOffset即可得到屏幕外UICollectionView的內(nèi)容.

最早實(shí)現(xiàn)的方法是,通過ContentOffset得到屏幕外的內(nèi)容生成一個(gè)StoryView,并且在下面加一個(gè)APP Logo的footerView.

這樣完整的一篇加角標(biāo)的文章長圖的StoryView就得到了,然后截圖.

但是!遇到的問題就是StoryView有時(shí)會出現(xiàn)黑色,經(jīng)過Google和查詢蘋果官方文檔.知道了問題的原因就是View的高度過高.

UIView Class Reference

NOTE

In iOS 2.x, the maximum size of aUIViewobject is 1024 x 1024 points. In iOS 3.0 and later, views are no longer restricted to this maximum size but are still limited by the amount of memory they consume. It is in your best interests to keep view sizes as small as possible. Regardless of which version of iOS is running, you should consider tiling any content that is significantly larger than the dimensions of the screen.

我個(gè)人測試大概是View高度超過4000+就會有問題(沒有特別精確,4000多一點(diǎn)點(diǎn)還是沒有問題,我這里以4000為準(zhǔn)).


紋理的渲染

所有的 Bitmap,包括圖片、文本、柵格化的內(nèi)容,最終都要由內(nèi)存提交到顯存,綁定為 GPU Texture。不論是提交到顯存的過程,還是 GPU 調(diào)整和渲染 Texture 的過程,都要消耗不少 GPU 資源。當(dāng)在較短時(shí)間顯示大量圖片時(shí)(比如 TableView 存在非常多的圖片并且快速滑動(dòng)時(shí)),CPU 占用率很低,GPU 占用非常高,界面仍然會掉幀。避免這種情況的方法只能是盡量減少在短時(shí)間內(nèi)大量圖片的顯示,盡可能將多張圖片合成為一張進(jìn)行顯示。

當(dāng)圖片過大,超過 GPU 的最大紋理尺寸時(shí),圖片需要先由 CPU 進(jìn)行預(yù)處理,這對 CPU 和 GPU 都會帶來額外的資源消耗。目前來說,iPhone 4S 以上機(jī)型,紋理尺寸上限都是 4096x4096,更詳細(xì)的資料可以看這里:iosres.com。所以,盡量不要讓圖片和視圖的大小超過這個(gè)值。

參考引用GuoYaoyuanBlog:iOS 保持界面流暢的技巧


然后轉(zhuǎn)換了思路通過"拼圖"的方式來解決長圖的問題.每一部分截一張圖.最后將所有的圖片拼接起來.

效果圖:

圖一:

最后附上相關(guān)代碼:

NSMutableArray*imageArray = [NSMutableArray array];

CGFloatoneImageHeight =2000.0f;

CGFloatstoryViewTotalHeight = (storyCollectionView.contentSize.height+ storyCollectionView.contentInset.top+ storyCollectionView.contentInset.bottom);

NSUIntegertotalImageCounts =ceilf( storyViewTotalHeight / oneImageHeight);

storyView.frame=CGRectMake(0,0,ScreenWidth, oneImageHeight);

[storyView layoutIfNeeded];

for(int i =0; i < totalImageCounts; i++) {

[storyCollectionViewsetContentOffset:CGPointMake(0, i * oneImageHeight - storyCollectionView.contentInset.top)];

if(i == totalImageCounts -1) {

UIGraphicsBeginImageContextWithOptions(CGSizeMake(ScreenWidth, storyViewTotalHeight - i * oneImageHeight),YES, imageSacle);

[storyViewdrawViewHierarchyInRect:storyView.frameafterScreenUpdates:YES];

}else{

UIGraphicsBeginImageContextWithOptions(storyView.bounds.size,YES, imageSacle);

[storyViewdrawViewHierarchyInRect:storyView.frameafterScreenUpdates:YES];

}

UIImage*image =UIGraphicsGetImageFromCurrentImageContext();

[imageArrayaddObject:image];

UIGraphicsEndImageContext();

}

//拼接長微博圖片

UIImage*image = imageArray[0];

for(inti =0; i < imageArray.count; i++) {

image = [StoryEditorViewControllercombine:image :imageArray[i+1]imageSacle:imageSacle];

if(i == imageArray.count-2) {

break;

}

}

+ (UIImage*)combine:(UIImage*)topImage :(UIImage*)bottomImage imageSacle:(CGFloat)imageSacle {

CGFloatwidth = topImage.size.width;

CGFloatheight = topImage.size.height+ bottomImage.size.height;

CGSizeoffScreenSize =CGSizeMake(width, height);

UIGraphicsBeginImageContextWithOptions(offScreenSize,YES, imageSacle);

CGRectrect =CGRectMake(0,0, width, topImage.size.height);

[topImagedrawInRect:rect];

rect.origin.y+= topImage.size.height;

CGRectrect1 =CGRectMake(0, rect.origin.y, width, bottomImage.size.height);

[bottomImagedrawInRect:rect1];

UIImage* imagez =UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return imagez;


}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容