iOS中關(guān)于截圖的注意點(renderInContext && drawViewHierarchyInRect)

截圖

關(guān)于截圖有兩個方法:

  • - (void)renderInContext:(CGContextRef)ctx: 作用于CALayer層的方法拨黔。將view的layer渲染到當(dāng)前的繪制的上下文中钱磅。

  • - (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates: 作用于UIView的方法杖爽。對view進行一個快照警没,然后將快照渲染到當(dāng)前的上下文中。

renderInContext就不說了锄俄,比較容易,只需要注意下UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)函數(shù)中的的size即可。

關(guān)鍵是- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates函數(shù)中多了一個描述位置的rect參數(shù)千贯,容易弄不清這個rectUIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)函數(shù)中的size的關(guān)系。之前一直沒有完全理解這兩個參數(shù)的區(qū)別搞坝,搜了很多資料發(fā)現(xiàn)都沒有人講清楚這兩個參數(shù)的含義搔谴,網(wǎng)上來來回回都是一些雷同的代碼,這次仔細測試研究了下桩撮,總結(jié)了下這兩個參數(shù)的含義敦第。

一般截圖的方法可以用例如下面這段代碼,對當(dāng)前控制的view進行截圖:

UIGraphicsBeginImageContextWithOptions(CGSizeMake(CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)), YES, 0.0);
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

先介紹下這兩個函數(shù)的含義:

UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) :開啟一個繪圖的上下文

  • size : size是指繪圖上下文的寬高店量,可以理解為要繪制圖形的畫布的大小

  • opaque : 是否透明芜果,如果傳YES,畫布的背景色為黑色融师,NO的時候右钾,畫布背景色是白色

  • scale:指的是繪制出來的圖片的像素比,決定了繪圖圖片的清晰度诬滩,一般填0.0霹粥,默認屏幕縮放比

- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates: 將要截屏的view繪制到當(dāng)前的上下文中。

rect:指定圖片繪制的坐標(biāo)

afterUpdates:截圖的瞬間是否將屏幕當(dāng)前的變更渲染進去

這個方法的是UIView的方法疼鸟,截圖的目標(biāo)對象就是當(dāng)前方法的調(diào)用者后控。

例如[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:NO]; 就是對self.view這個對象進行截圖,會把self.view 當(dāng)前的這個view全部截取下來然后繪制到當(dāng)前的上下文中生成圖片空镜,然后按照這個方法中指定的rect 為frame浩淘,以畫布為父視圖繪制到畫布中去捌朴。

注意:截圖截取的是drawViewHierarchyInRect這個方法調(diào)用的view,而渲染出來的效果(圖片的位置和大姓懦)是由UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)中的size和- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates中的rect共同決定的砂蔽。

例如,我們要截取下面屏幕中的照片(請忽略被變形的照片...)

image

代碼如下:

注:

self.view是當(dāng)前控制器的view

self.screenshotImgV 是上面的圖片的UIImageView署惯。self.screenshotImgV的frame是:(50, 37, 275, 489)

為了方便理解左驾,下面用畫布來指代繪制的上下文

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, 1, 0.0);
[self.screenshotImgV drawViewHierarchyInRect:self.screenshotImgV.frame afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

如上指定畫布的大小為當(dāng)前self.view的大小极谊,對self.screenshotImgV進行截圖诡右,同時設(shè)置截圖后的圖片在畫布中的位置為自身的frame。

截圖效果:

image

由于self.view的大小是大于當(dāng)前self.screenshotImgV的大小轻猖,所以對self.screenshotImgV進行截圖繪制后帆吻,并不能充滿整個畫布,只能占據(jù)其中的一部分咙边。而占據(jù)的位置依據(jù)的就是drawViewHierarchyInRect方法中指定的rect猜煮。這個例子中指定的是self.screenshotImgV.frame,也即:(50, 37, 275, 489) 這個frame败许,所以就展示如上面效果王带。

下面我們來調(diào)整下指定的rect, 讓其為self.screenshotImgV.bounds檐束,看看效果辫秧。

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, 1, 0.0);
[self.screenshotImgV drawViewHierarchyInRect:self.screenshotImgV.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

截圖效果:

image

如上圖,由于rect用的是self.screenshotImgV.bounds被丧,所以截圖的坐標(biāo)的xy變?yōu)榱?code>(0, 0),也就是圖片的起始位置變?yōu)榱俗钭笊辖恰?/p>

下面我們來換一下绪妹,把畫布的大小設(shè)置為self.screenshotImgV的大小甥桂,然后對self.view進行截圖,看看效果:

UIGraphicsBeginImageContextWithOptions(self.screenshotImgV.bounds.size, 1, 0.0);
[self.view drawViewHierarchyInRect:self.screenshotImgV.frame afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

截圖效果:

image

如上邮旷,由于rect指定為self.screenshotImgV.frame黄选,只能從(50, 37)這個位置開始渲染,所以在截圖的時候只能截取self.view中的一部分婶肩,另外一部分超出畫布范圍截取不到办陷。如果frame的坐標(biāo)是從(0,0)開始效果如何呢?

UIGraphicsBeginImageContextWithOptions(self.screenshotImgV.bounds.size, 1, 0.0);
[self.view drawViewHierarchyInRect:self.screenshotImgV.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

截圖效果:

image

發(fā)現(xiàn)剛好把self.view完整的渲染出來了。這是因為UIGraphicsBeginImageContextWithOptions方法中的sizedrawViewHierarchyInRect中指定的rect.size大小相同律歼,而且rectx,y都是(0,0)民镜,所以截取的self.view從左上角起始位置開始渲染,剛好能夠把整個畫布充滿险毁,全部渲染出來制圈。

通過上面的例子们童,應(yīng)你能弄清楚UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)中的size- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates中的rect的意義和關(guān)系了吧。

當(dāng)然對于這個例子鲸鹦,如果我們想截取屏幕中的圖片self.screenshotImgV慧库,只需要把尺寸都指定為self.screenshotImgVsize既可:

UIGraphicsBeginImageContextWithOptions(self.screenshotImgV.bounds.size, 1, 0.0);
[self.screenshotImgV drawViewHierarchyInRect:self.screenshotImgV.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

截圖效果:

image

裁剪圖片

裁剪圖片就是對當(dāng)前的圖片按照指定的大小范圍生成一個新的圖片,方法如下:

- (UIImage *)createImageWithRect:(CGRect)rect image:(UIImage *)clipImage {
    CGImageRef imageRef = CGImageCreateWithImageInRect(clipImage.CGImage, rect);
    UIImage *image = [UIImage imageWithCGImage:imageRef scale:clipImage.scale orientation:UIImageOrientationUp];
    CGImageRelease(imageRef);
    return image;
}

這里的rect就是指定的裁剪范圍馋嗜。方法比較簡單齐板,沒有什么好解釋的。主要注意的是葛菇,這里rect包含的x,y,width,height應(yīng)該是圖片的絕對尺寸乘以圖片的縮放因子甘磨,否則裁剪出來的圖片是不對的。如果圖片是1倍圖會沒什么問題熟呛,但是如果是2倍圖或者3倍圖宽档,要么可能尺寸不對,要么截出來的圖片很模糊庵朝。完整方法可改為:

- (UIImage *)createImageWithRect:(CGRect)rect image:(UIImage *)clipImage {
    rect.origin.x *= clipImage.scale;
    rect.origin.y *= clipImage.scale;
    rect.size.width *= clipImage.scale;
    rect.size.height *= clipImage.scale;
    CGImageRef imageRef = CGImageCreateWithImageInRect(clipImage.CGImage, rect);
    UIImage *image = [UIImage imageWithCGImage:imageRef scale:clipImage.scale orientation:UIImageOrientationUp];
    CGImageRelease(imageRef);
    return image;
}

其他注意點:

WKWebView

  • 對于WKWebView使用 renderInContext的方法進行截圖的時候吗冤, 當(dāng)WKWebView 執(zhí)行UIGraphicsGetCurrentContext()的結(jié)果返回的nil,截圖失敗

  • 所以只能UIViewdrawViewHierarchyInRect的方法去截圖

UIVisualEffectView九府,高斯模糊蒙版

  • 對于使用了UIBlurEffect進行高斯模糊的UIView進行截圖的時候椎瘟,如果對view.layer使用 renderInContext的方法進行截圖,上面的高斯模糊蒙版會失真失效侄旬,可以改用drawViewHierarchyInRect方法肺蔚,這樣能夠保持高斯模糊的效果。相對于renderInContext是對view的layer渲染到當(dāng)前的上下文中儡羔,drawViewHierarchyInRect方法是對view進行一個快照宣羊,然后將快照渲染到當(dāng)前的上下文中。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末汰蜘,一起剝皮案震驚了整個濱河市仇冯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌族操,老刑警劉巖苛坚,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異色难,居然都是意外死亡泼舱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門枷莉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娇昙,“玉大人,你說我怎么就攤上這事依沮⊙恼辏” “怎么了枪狂?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宋渔。 經(jīng)常有香客問我州疾,道長,這世上最難降的妖魔是什么皇拣? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任严蓖,我火速辦了婚禮,結(jié)果婚禮上氧急,老公的妹妹穿的比我還像新娘颗胡。我一直安慰自己,他們只是感情好吩坝,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布毒姨。 她就那樣靜靜地躺著,像睡著了一般钉寝。 火紅的嫁衣襯著肌膚如雪弧呐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天嵌纲,我揣著相機與錄音俘枫,去河邊找鬼。 笑死逮走,一個胖子當(dāng)著我的面吹牛鸠蚪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播师溅,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼茅信,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了墓臭?” 一聲冷哼從身側(cè)響起汹押,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎起便,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窖维,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡榆综,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铸史。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鼻疮。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖琳轿,靈堂內(nèi)的尸體忽然破棺而出判沟,到底是詐尸還是另有隱情耿芹,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布挪哄,位于F島的核電站吧秕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏迹炼。R本人自食惡果不足惜砸彬,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斯入。 院中可真熱鬧砂碉,春花似錦、人聲如沸刻两。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磅摹。三九已至滋迈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間偏瓤,已是汗流浹背杀怠。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厅克,地道東北人赔退。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像证舟,于是被迫代替她去往敵國和親硕旗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容