亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁(yè) > 系統(tǒng) > iOS > 正文

iOS使用WebView生成長(zhǎng)截圖的第3種解決方案

2019-10-21 18:39:41
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

前言

WebView就是一個(gè)內(nèi)嵌瀏覽器控件,在iOS中主要有兩種WebView:UIWebView和WKWebView,UIWebView是iOS2之后開(kāi)始使用,WKWebView是在iOS8開(kāi)始使用,WKWebView將逐步取代笨重的UIWebView。

由于項(xiàng)目需要,新近實(shí)現(xiàn)了一個(gè)長(zhǎng)截圖庫(kù) SnapshotKit。其中,需要支持 UIWebView、WKWebView 組件生成長(zhǎng)截圖。為了實(shí)現(xiàn)這個(gè)特性,查閱了很多資料,同時(shí)也做了不同的新奇思路嘗試,最終實(shí)現(xiàn)了一個(gè)新的、取巧的技術(shù)方案。

以下主要總結(jié)了在“WebView生成長(zhǎng)截圖”需求方面,“網(wǎng)上已有方案”和“我的全新方案”的各自實(shí)現(xiàn)要點(diǎn)和優(yōu)缺點(diǎn)。

WebView生成長(zhǎng)截圖的已有方案

根據(jù) Google 所搜索到的資料,目前iOS WebView生成長(zhǎng)截圖的方案主要有2種:

  • 方案一:修改Frame,截圖組件
  • 方案二:分頁(yè)截圖組件內(nèi)容,合成長(zhǎng)圖

下面將會(huì)簡(jiǎn)述方案一和方案二的具體實(shí)現(xiàn)。

方案一:修改Frame,截圖組件

方案一的實(shí)現(xiàn)要點(diǎn)在于:修改 webView.scrollView 的 frameSize  為 contentSize,然后對(duì)整個(gè) webView.scrollView 進(jìn)行截圖。

不過(guò),這個(gè)方案只適用 UIWebView 組件,因?yàn)槠涫且淮涡约虞d網(wǎng)頁(yè)所有的內(nèi)容。而 WKWebView 組件,為了節(jié)省內(nèi)存,加載網(wǎng)頁(yè)內(nèi)容時(shí),只加載可視部分——這一點(diǎn)類(lèi)似 UITableView 組件。在修改webView.scrollView 的 frameSize 后,立即執(zhí)行了截圖操作, 這時(shí)候,WKWebView由于還沒(méi)把網(wǎng)頁(yè)的內(nèi)容加載出來(lái),導(dǎo)致生成的長(zhǎng)截圖是空白的。

方案一核心代碼如下:

extension UIScrollView { public func takeSnapshotOfFullContent() -> UIImage? {  let originalFrame = self.frame  let originalOffset = self.contentOffset  self.frame = CGRect.init(origin: originalFrame.origin, size: self.contentSize)  self.contentOffset = .zero  let backgroundColor = self.backgroundColor ?? UIColor.white  UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0)  guard let context = UIGraphicsGetCurrentContext() else {   return nil  }  context.setFillColor(backgroundColor.cgColor)  context.setStrokeColor(backgroundColor.cgColor)  self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)  let image = UIGraphicsGetImageFromCurrentImageContext()  UIGraphicsEndImageContext()  self.frame = originalFrame  self.contentOffset = originalOffset  return image }}

測(cè)試代碼:

// example code private func takeSnapshotOfUIWebView() { let image = self.webView.scrollView.takeSnapshotOfFullContent() // 處理image} 

方案二:分頁(yè)截圖組件內(nèi)容,合成長(zhǎng)圖

方案二的實(shí)現(xiàn)要點(diǎn)在于:分頁(yè)滾動(dòng)WebView組件的內(nèi)容,然后生成分頁(yè)截圖,最后把所有分頁(yè)截圖合成一張長(zhǎng)圖。

這個(gè)方案適用于 UIWebView 組件和 WKWebView 組件。

方案二核心代碼如下:

extension UIScrollView { public func takeScreenshotOfFullContent(_ completion: @escaping ((UIImage?) -> Void)) {  // 分頁(yè)繪制內(nèi)容到ImageContext  let originalOffset = self.contentOffset  // 當(dāng)contentSize.height<bounds.height時(shí),保證至少有1頁(yè)的內(nèi)容繪制  var pageNum = 1  if self.contentSize.height > self.bounds.height {   pageNum = Int(floorf(Float(self.contentSize.height / self.bounds.height)))  }  let backgroundColor = self.backgroundColor ?? UIColor.white  UIGraphicsBeginImageContextWithOptions(self.contentSize, true, 0)  guard let context = UIGraphicsGetCurrentContext() else {   completion(nil)   return  }  context.setFillColor(backgroundColor.cgColor)  context.setStrokeColor(backgroundColor.cgColor)  self.drawScreenshotOfPageContent(0, maxIndex: pageNum) {   let image = UIGraphicsGetImageFromCurrentImageContext()   UIGraphicsEndImageContext()   self.contentOffset = originalOffset   completion(image)  } } fileprivate func drawScreenshotOfPageContent(_ index: Int, maxIndex: Int, completion: @escaping () -> Void) {  self.setContentOffset(CGPoint(x: 0, y: CGFloat(index) * self.frame.size.height), animated: false)  let pageFrame = CGRect(x: 0, y: CGFloat(index) * self.frame.size.height, width: self.bounds.size.width, height: self.bounds.size.height)  DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {   self.drawHierarchy(in: pageFrame, afterScreenUpdates: true)   if index < maxIndex {    self.drawScreenshotOfPageContent(index + 1, maxIndex: maxIndex, completion: completion)   }else{    completion()   }  } }}

測(cè)試代碼:

// example codeprivate func takeSnapshotOfUIWebView() { self.uiWebView.scrollView.takeScreenshotOfFullContent { (image) in  // 處理image }}private func takeSnapshotOfWKWebView() { self.wkWebView.scrollView.takeScreenshotOfFullContent { (image) in  // 處理image }}

WebView生成長(zhǎng)截圖的新方案

除了方案一和方案二,還有新方案嗎?

答案是肯定加確定以及一定的。

這個(gè)新方案的要點(diǎn)在于:iOS系統(tǒng)的WebView打印功能。

iOS系統(tǒng)支持把WebView的內(nèi)容打印到PDF文件上,借助這個(gè)特性,新方案的設(shè)計(jì)如下:

  • 把 WebView組件的內(nèi)容全部打印到一頁(yè)P(yáng)DF上
  • 把PDF轉(zhuǎn)換成圖片

新方案的核心代碼如下:

import UIKitimport WebKit/// WebViewPrintPageRenderer: use to print the full content of webview into one imageinternal final class WebViewPrintPageRenderer: UIPrintPageRenderer { private var formatter: UIPrintFormatter private var contentSize: CGSize /// 生成PrintPageRenderer實(shí)例 /// /// - Parameters: /// - formatter: WebView的viewPrintFormatter /// - contentSize: WebView的ContentSize required init(formatter: UIPrintFormatter, contentSize: CGSize) {  self.formatter = formatter  self.contentSize = contentSize  super.init()  self.addPrintFormatter(formatter, startingAtPageAt: 0) } override var paperRect: CGRect {  return CGRect.init(origin: .zero, size: contentSize) } override var printableRect: CGRect {  return CGRect.init(origin: .zero, size: contentSize) } private func printContentToPDFPage() -> CGPDFPage? {  let data = NSMutableData()  UIGraphicsBeginPDFContextToData(data, self.paperRect, nil)  self.prepare(forDrawingPages: NSMakeRange(0, 1))  let bounds = UIGraphicsGetPDFContextBounds()  UIGraphicsBeginPDFPage()  self.drawPage(at: 0, in: bounds)  UIGraphicsEndPDFContext()  let cfData = data as CFData  guard let provider = CGDataProvider.init(data: cfData) else {   return nil  }  let pdfDocument = CGPDFDocument.init(provider)  let pdfPage = pdfDocument?.page(at: 1)  return pdfPage } private func covertPDFPageToImage(_ pdfPage: CGPDFPage) -> UIImage? {  let pageRect = pdfPage.getBoxRect(.trimBox)  let contentSize = CGSize.init(width: floor(pageRect.size.width), height: floor(pageRect.size.height))  // usually you want UIGraphicsBeginImageContextWithOptions last parameter to be 0.0 as this will us the device's scale  UIGraphicsBeginImageContextWithOptions(contentSize, true, 2.0)  guard let context = UIGraphicsGetCurrentContext() else {   return nil  }  context.setFillColor(UIColor.white.cgColor)  context.setStrokeColor(UIColor.white.cgColor)  context.fill(pageRect)  context.saveGState()  context.translateBy(x: 0, y: contentSize.height)  context.scaleBy(x: 1.0, y: -1.0)  context.interpolationQuality = .low  context.setRenderingIntent(.defaultIntent)  context.drawPDFPage(pdfPage)  context.restoreGState()  let image = UIGraphicsGetImageFromCurrentImageContext()  UIGraphicsEndImageContext()  return image } /// print the full content of webview into one image /// /// - Important: if the size of content is very large, then the size of image will be also very large /// - Returns: UIImage? internal func printContentToImage() -> UIImage? {  guard let pdfPage = self.printContentToPDFPage() else {   return nil  }  let image = self.covertPDFPageToImage(pdfPage)  return image }}extension UIWebView { public func takeScreenshotOfFullContent(_ completion: @escaping ((UIImage?) -> Void)) {  self.scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)  DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {   let renderer = WebViewPrintPageRenderer.init(formatter: self.viewPrintFormatter(), contentSize: self.scrollView.contentSize)   let image = renderer.printContentToImage()   completion(image)  } }}extension WKWebView { public func takeScreenshotOfFullContent(_ completion: @escaping ((UIImage?) -> Void)) {  self.scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)  DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {   let renderer = WebViewPrintPageRenderer.init(formatter: self.viewPrintFormatter(), contentSize: self.scrollView.contentSize)   let image = renderer.printContentToImage()   completion(image)  } }}

WebViewPrintPageRenderer 是該方案的核心類(lèi),負(fù)責(zé)把 WebView組件內(nèi)容打印到PDF,然后把PDF轉(zhuǎn)換為圖片。
UIWebView 和 WKWebView 則實(shí)現(xiàn)對(duì)應(yīng)的擴(kuò)展。

測(cè)試代碼:

// example codeprivate func takeSnapshotOfUIWebView() { self.uiWebView.scrollView.takeScreenshotOfFullContent { (image) in  // 處理image }}private func takeSnapshotOfWKWebView() { self.wkWebView.scrollView.takeScreenshotOfFullContent { (image) in  // 處理image }}

三種技術(shù)方案優(yōu)劣對(duì)比

那么,這三種技術(shù)方案各自存在什么優(yōu)缺點(diǎn)呢,適用什么場(chǎng)景呢?

方案一:只適用 UIWebView;若網(wǎng)頁(yè)內(nèi)容很多,生成長(zhǎng)截圖時(shí),會(huì)占用過(guò)多內(nèi)存。 所以,該方案只適合不需要支持 WKWebView, 且網(wǎng)頁(yè)內(nèi)容不會(huì)太多的場(chǎng)景。

方案二:適用 UIWebView 和 WKWebView,且特別適合 WKWebView。由于采用分頁(yè)生成截圖機(jī)制,有效減少內(nèi)存占用。不過(guò),這個(gè)方案存在一個(gè)問(wèn)題:若網(wǎng)頁(yè)存在 position: fixed 的元素(如網(wǎng)頁(yè)頭部固定的導(dǎo)航欄),該元素會(huì)重復(fù)出現(xiàn)在生成的長(zhǎng)圖上。

方案三:適用 UIWebView 和 WKWebView。其中最重要的一步——“把WebView內(nèi)容打印到PDF” 是由iOS系統(tǒng)實(shí)現(xiàn),所以該方案的性能在理論上是可以得到保障的。不過(guò),這個(gè)方案存在一個(gè)問(wèn)題:在把網(wǎng)頁(yè)內(nèi)容打印到PDF時(shí),iOS系統(tǒng)獲取的 contentSize 比WebView的實(shí)際contentSize 要大,從而導(dǎo)致生成的圖片在靠近底部的內(nèi)容部分和實(shí)際存在一點(diǎn)差異。具體可以下載運(yùn)行我的長(zhǎng)截圖庫(kù) SnapshotKit 的 Demo,通過(guò)其中的 UIWebView 和 WKWebView 截圖示例查看具體截圖效果。

以上三個(gè)方案,總的來(lái)說(shuō),解決了部分場(chǎng)景的需求,但都不夠完美,仍需做進(jìn)一步的優(yōu)化。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)VEVB武林網(wǎng)的支持。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到IOS開(kāi)發(fā)頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产精品扒开腿做爽爽爽视频软件| 在线永久免费观看黄网站| 91青青在线视频| 国产黄色片在线播放| 在线免费看黄色片| 91视频欧美| 日本美女一区二区三区| 国产精品国产三级国产aⅴ9色| 黄色在线资源| 天天综合在线观看| 国产亚洲精品美女久久久m| 国产在线观看福利| 中文字幕av在线| 艳妇臀荡乳欲伦亚洲一区| 亚洲视频精选| 欧美另类videosbest视频| 小香蕉视频在线| 亚洲 欧美 激情 小说 另类| 成人精品影视| 亚洲国产经典视频| 欧美精品一区二区三区在线四季| 综合视频一区| 久久精品国语| 成人福利网站在线观看| 欧美日韩免费在线视频| 91成人在线观看喷潮教学| 91九色美女在线视频| www.男人天堂网| 日韩免费大片| 真不卡电影网| 三级影片在线观看| 成人黄色av免费在线观看| 欧美电影免费观看高清完整| 亚洲一区二区激情| 国内精品一区视频| 日韩女同互慰一区二区| 922tv免费观看在线| 欧美日韩午夜精品| 欧美亚洲日本在线观看| 欧美国产精品一区二区三区| 欧美日韩精品一区二区天天拍小说| 国产视频精品免费播放| 日韩欧美高清在线| 久久久久久久激情| 欧美黄色一级生活片| 欧美日韩第一区| 看全色黄大色黄大片免责看的| 日本50路肥熟bbw| 欧美三级电影一区二区三区| 国产精品久久久久毛片大屁完整版| 蜜桃久久av一区| 国产cdts系列另类在线观看| 精品国产乱码久久久久久108| 天天色综合久久| 久久九九国产视频| 女人抽搐喷水高潮国产精品| 日韩精品在线观看av| 91久久免费视频| 国产精品观看在线亚洲人成网| 日本中文在线播放| 妞干网在线免费视频| 欧美电影一区二区三区| 国产精品一区二区免费看| 免费看ww视频网站入口| 宅男在线国产精品| 不卡视频在线观看| 自拍偷拍欧美日韩| 亚州av电影免费在线观看| 亚洲国产精品一区二区第一页| 日韩精品一卡二卡三卡四卡无卡| 国产大陆a不卡| 99只有精品| 久久天堂国产精品| 蜜臀av中文字幕| 久久久久久国产三级电影| 国产成人高清| 国产又大又黄又粗的视频| 精品国产亚洲一区二区在线观看| 日韩在线第三页| 四季av一区二区三区免费观看| 在线激情影院一区| 黄色a级三级三级三级| 久久视频一区二区| 啪啪国产精品| 亚洲一区站长工具| 国产精品久久久av久久久| 日韩最新免费不卡| 久久精品这里都是精品| 成人一区二区三区中文字幕| 另类调教123区| 一区二区三区在线观看动漫| 免费成人在线网站| 一区二区三区国产好的精华液| 国产三级短视频| 色爱综合av| 国产在线一在线二| 911久久香蕉国产线看观看| 欧美疯狂性受xxxxx另类| 影音先锋电影在线观看| 午夜精品在线视频| 精品视频一区二区在线| 麻豆传媒在线观看| 国产精品xxx电影| 久久精品青草| 成熟人妻av无码专区| 91在线一区| 性欧美丰满熟妇xxxx性仙踪林| 日本免费网站在线观看| 一区二区精品在线| 亚洲一二三四2021不卡| 国产福利久久久| 日韩毛片高清在线播放| 欧美性感美女h网站在线观看免费| 精品人妻伦一区二区三区久久| 亚洲图色一区二区三区| 91福利视频免费观看| 国产精品视频久久久久久| 黄网av在线| 亚洲a v网站| 天堂8中文在线最新版在线| 亚洲国产精品一区制服丝袜| 99精品国产热久久91蜜凸| 久久久久久高潮国产精品视| 久久蜜桃av一区精品变态类天堂| 最近中文字幕在线观看视频| 中文字幕有码在线观看| 中国女人内谢69xxxx免费视频| 久久97超碰国产精品超碰| 日韩视频免费观看高清在线视频| 欧美成人三级在线播放| 欧美精品资源| a级黄色毛片| 亚洲欧美一区二区三区在线| 97成人超碰| 日本一区二区不卡| 不卡在线视频中文字幕| 看av免费毛片手机播放| 午夜欧美在线一二页| 最近中文字幕大全中文字幕免费| 国产女主播喷水视频在线观看| 国产精品视频一| 国产精品激情| 国产精品人人爽人人做我的可爱| 每日在线更新av| 九九热在线免费观看| 久久电影视频| 99久久久久成人国产免费| 国产又色又爽又高潮免费| 欧美日韩国产小视频| 亚洲第一天堂网| 欧美老熟妇乱大交xxxxx| 在线观看中文字幕视频| 尤物视频免费在线观看| 3344国产永久在线观看视频| 亚洲欧洲精品一区二区三区波多野1战4| 我要看黄色一级片| 四虎影视4hu4虎成人| 羞羞网站在线免费观看| 亚洲综合视频在线播放| 调教+趴+乳夹+国产+精品| 免费视频91| 性欧美xxxx免费岛国不卡电影| 疯狂做受xxxⅹ高潮视频免费| 国产色在线播放| 欧美1区二区三区公司| 国产va在线观看| 亚洲国产精品久| 欧美激情在线一区二区| 欧美性受xxxx黒人xyx性爽| 日韩av影视在线| 久草视频在线资源站| 国产在线拍偷自揄拍精品| 宅男在线观看免费高清网站| 亚洲一区二区高清视频| 国产成人高清精品免费5388| 亚洲男人天堂一区| 四虎影在永久在线观看| 国产麻豆9l精品三级站| 亚洲视频精选| 精品亚洲精品福利线在观看| 中文在线不卡| 亚洲日本视频在线观看| 国产伦精品一区二区三区视频黑人| 成人av免费在线| 亚洲精品免费一区亚洲精品免费精品一区| 欧美大胆a人体大胆做受| 天天综合天天综合| 亚洲乱码国产一区三区| 久久精品国产www456c0m| 午夜剧场成人观在线视频免费观看| 麻豆成人免费视频| 国产大学生校花援交在线播放| 亚洲人视频在线观看| 免费在线观看视频一区| 四虎国产成人精品免费一女五男| 亚洲精品美女91| 波多野结衣免费观看| 国产一区二区三区蝌蚪| 成人在线免费观看视频网站| 国产农村av| 久久久99精品免费观看不卡| **毛片在线网站| 性生大片免费观看性| 最后生还者第二季在线观看| 亚洲av人无码激艳猛片服务器| 在线免费观看av影视天堂| 久久国产精品免费| 色视频www在线播放| 一区二区在线视频| 99欧美精品| 亚洲ab电影| 中文字幕在线观看不卡视频| 久久黄色小视频| 国产v综合ⅴ日韩v欧美大片| 日韩中文欧美在线| 无码人妻精品一区二区三应用大全| 色综合视频一区二区三区日韩| 美女视频黄的免费| 色帝国亚洲欧美在线| 久久99精品久久久久婷婷| 亚洲澳门在线| 亚洲色图色老头| 在线观看wwww| 亚洲午夜福利在线观看| 欧美激情极品| 欧美深夜福利| 2023国产精品视频| 精品肉丝脚一区二区三区| 91黄视频在线| 99久久精品国产毛片| 欧美成人三级| 国内一区二区在线| 亚洲欧美综合国产精品一区| 免费看黄色aaaaaa 片| 亚洲欧美日韩一区二区三区在线观看| 日韩va亚洲va欧洲va国产| 欧美一区二区三区免费观看视频| 丝袜美腿亚洲一区二区图片| 亚洲一二在线观看| 久草在线成人| 免费国产成人av| 理论电影国产精品| 成人午夜sm精品久久久久久久| 日日躁夜夜躁aaaabbbb| 国户精品久久久久久久久久久不卡| av高清不卡| qvod激情图片| 免费看污片的网站| 欧美午夜激情影院| 欧美精品在欧美一区二区少妇| 欧美电影免费观看完整版| 99精品国产99久久久久久福利| 2018中文字幕在线| 亚洲一区电影在线观看| 日韩亚洲欧美综合| 国产女主播在线| 蜜桃传媒一区二区亚洲| 秋霞av国产精品一区| 亚洲天堂资源在线| 波多野结衣家庭教师视频| 成av人片一区二区| 欧美精品亚洲精品日韩精品| 国内精品久久久久久久久| 男男gay无套免费视频欧美| 久久久久亚洲av无码专区喷水| eeuss影院www在线观看手机| 11024精品一区二区三区日韩| 亚洲七七久久综合桃花剧情介绍| 国产精品白嫩初高中害羞小美女| 国产精品久久久久久久久果冻传媒| 国产三级三级三级看三级| 日韩超碰人人爽人人做人人添| 成人欧美一区二区三区黑人免费| 99精品视频在线观看免费播放| 日韩一级免费毛片| 在线观看中文字幕2021| 在线观看v片| 日本黄色录像片| 国产精品流白浆在线观看| 欧美激情偷拍| 久久久久影视| 青青青国产精品| 小早川怜子痴女在线精品视频| 1024国产在线| 欧美极品少妇xxxxⅹ免费视频| 亚洲精品自拍视频在线观看| 国产午夜亚洲精品午夜鲁丝片| 精品久久久久久国产91| 一区二区视频在线免费| 国产日韩亚洲欧美在线| a资源在线观看| 中文字幕9999| 韩国一区二区电影| 91九色精品视频| 亚洲国产成人精品综合99| 蜜臀aⅴ国产精品久久久国产老师| 精品无码国产污污污免费网站| 久久免费看少妇高潮| 色多多国产成人永久免费网站| 欧美国产日韩一区二区在线观看| 精品国产导航| 久蕉在线视频| 国内精品亚洲| 91av俱乐部| 中文字幕在线亚洲精品| a级影片在线观看| 欧美国产日韩在线视频| 青青草原国产在线观看| 国产成人亚洲综合色影视| 国产精品伦一区二区三级视频| 波多野结衣高清在线| 亚洲精品高清无码视频| 国产成人精品一区二区三区在线观看| a美女胸又www黄视频久久| 欧美极品美女电影一区| 国产叼嘿视频在线观看| 色呦呦在线播放| 一级黄色片国产| 精品久久久久久中文字幕人妻最新| 在线免费亚洲电影| 国产一区啦啦啦在线观看| 91丨porny丨首页| 在线免费播放av| 国产在视频线精品视频| 亚洲精品乱码久久| 免费在线性爱视频| 日本午夜免费一区二区| 免费在线视频一区二区|