sách gpt4 ăn đã đi

Giải pháp thứ ba cho iOS sử dụng WebView để tạo ảnh chụp màn hình dài

In lại Tác giả: qq735679552 Thời gian cập nhật: 28-09-2022 22:32:09 26 4
mua khóa gpt4 giày nike

CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.

Bài viết blog CFSDN này Giải pháp thứ ba cho việc sử dụng WebView để tạo ảnh chụp màn hình dài trên iOS đã được tác giả sưu tầm và biên soạn. Nếu bạn quan tâm đến bài viết này, hãy nhớ thích nó.

Lời nói đầu.

WebView là một điều khiển trình duyệt nhúng. Có hai loại WebView chính trong iOS: UIWebView và WKWebView đã bắt đầu được sử dụng sau iOS2 và WKWebView đã bắt đầu được sử dụng trong iOS8.

Do nhu cầu của dự án, SnapshotKit, một thư viện ảnh chụp màn hình dài, gần đây đã được triển khai. Trong số đó, cần hỗ trợ các thành phần UIWebView và WKWebView để tạo ảnh chụp màn hình dài. Để hiện thực hóa tính năng này, tôi đã tham khảo rất nhiều thông tin và thử nghiệm nhiều ý tưởng mới lạ khác nhau, cuối cùng tôi đã nhận ra một giải pháp kỹ thuật mới và thông minh.

Phần sau đây chủ yếu tóm tắt các điểm triển khai tương ứng, ưu điểm và nhược điểm của "các giải pháp hiện có trên Internet" và "giải pháp mới của tôi" về nhu cầu "WebView để tạo ảnh chụp màn hình dài".

Hiện có một giải pháp để tạo ảnh chụp màn hình dài bằng WebView.

Theo thông tin tìm kiếm trên Google, hiện nay có 2 cách chính để tạo ảnh chụp màn hình dài bằng iOS WebView:

  • Tùy chọn 1: Sửa đổi các thành phần Khung và ảnh chụp màn hình
  • Cách 2: Phân trang nội dung thành phần ảnh chụp màn hình và tổng hợp ảnh dài

Việc thực hiện cụ thể Đề án 1 và Đề án 2 sẽ được mô tả ngắn gọn dưới đây.

Tùy chọn 1: Sửa đổi các thành phần Khung và ảnh chụp màn hình.

Các điểm chính khi triển khai giải pháp một là: sửa đổi frameSize của webView.scrollView thành contentSize, sau đó chụp ảnh màn hình của toàn bộ webView.scrollView.

Tuy nhiên, giải pháp này chỉ áp dụng cho thành phần UIWebView vì nó tải tất cả nội dung của trang web cùng một lúc. Thành phần WKWebView, để tiết kiệm bộ nhớ, chỉ tải phần hiển thị khi tải nội dung trang web - điều này tương tự như thành phần UITableView. Sau khi sửa đổi frameSize của webView.scrollView, thao tác chụp ảnh màn hình ngay lập tức được thực hiện. Lúc này, WKWebView chưa tải nội dung của trang web nên ảnh chụp màn hình dài được tạo ra bị trống.

Mã cốt lõi của giải pháp một như sau:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
phần mở rộng UIScrollView {
  công cộng hàm takeSnapshotOfFullContent() -> UIImage? {
   để originalFrame = self.frame
   hãy để originalOffset = self.contentOffset
 
   self.frame = CGRect.init(nguồn gốc: originalFrame.origin, kích thước: self.contentSize)
   self.contentOffset = .zero
 
   hãy để backgroundColor = self.backgroundColor ?? UIColor.white
 
   UIGraphicsBeginImageContextWithOptions(self.bounds.size, ĐÚNG VẬY , 0)
 
   bảo vệ cho ngữ cảnh = UIGraphicsGetCurrentContext() khác {
    trở lại không
   }
   bối cảnh.setFillColor(backgroundColor.cgColor)
   bối cảnh.setStrokeColor(backgroundColor.cgColor)
 
   self.drawHierarchy(trong: self.bounds, afterScreenUpdates: ĐÚNG VẬY )
   hãy để hình ảnh = UIGraphicsGetImageFromCurrentImageContext()
   UIGraphicsEndImageContext()
 
   self.frame = originalFrame
   self.contentOffset = originalOffset
 
   trở lại hình ảnh
  }
}

Mã kiểm tra:

?
1
2
3
4
5
// mã ví dụ
  riêng tư hàm takeSnapshotOfUIWebView() {
  hãy để hình ảnh = self.webView.scrollView.takeSnapshotOfFullContent()
  // xử lý hình ảnh
}

Cách 2: Chụp ảnh màn hình phân trang của nội dung thành phần và ghép lại thành một ảnh dài.

Các điểm chính của việc triển khai giải pháp thứ hai là: cuộn nội dung của thành phần WebView trong các trang, sau đó tạo ảnh chụp màn hình trang và cuối cùng kết hợp tất cả ảnh chụp màn hình trang thành một ảnh dài.

Giải pháp này áp dụng cho các thành phần UIWebView và các thành phần WKWebView.

Mã cốt lõi của tùy chọn 2 như sau:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
phần mở rộng UIScrollView {
  công cộng func takeScreenshotOfFullContent(_ hoàn thành: @escaping ((UIImage?) -> Void)) {
   //Trang vẽ nội dung vào ImageContext
   hãy để originalOffset = self.contentOffset
 
   // Khi contentSize.height
   var trangNum = 1
   nếu như self.contentSize.height > self.bounds.height {
    pageNum = Int(floorf(Float(self.contentSize.height / self.bounds.height)))
   }
 
   hãy để backgroundColor = self.backgroundColor ?? UIColor.white
 
   UIGraphicsBeginImageContextWithOptions(self.contentSize, ĐÚNG VẬY , 0)
 
   bảo vệ cho ngữ cảnh = UIGraphicsGetCurrentContext() khác {
    hoàn thành(nil)
    trở lại
   }
   bối cảnh.setFillColor(backgroundColor.cgColor)
   bối cảnh.setStrokeColor(backgroundColor.cgColor)
 
   self.drawScreenshotOfPageContent(0, maxIndex: pageNum) {
    hãy để hình ảnh = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    self.contentOffset = originalOffset
    hoàn thành(hình ảnh)
   }
  }
 
  fileprivate func drawScreenshotOfPageContent(_ index: Int, maxIndex: Int, hoàn thành: @escaping () -> Void) {
 
   self.setContentOffset(CGPoint(x: 0, y: CGFloat(index) * self.frame.size.height), hoạt hình: SAI )
   hãy để pageFrame = CGRect(x: 0, y: CGFloat(index) * self.frame.size.height, width: self.bounds.size.width, height: self.bounds.size.height)
 
   DispatchQueue.main.asyncAfter(hạn chót: DispatchTime.now() + 0,3) {
    self.drawHierarchy(trong: pageFrame, afterScreenUpdates: ĐÚNG VẬY )
 
    nếu như chỉ số < maxIndex {
     self.drawScreenshotOfPageContent(index + 1, maxIndex: maxIndex, hoàn thành: hoàn thành)
    } khác {
     hoàn thành()
    }
   }
  }
}

Mã kiểm tra:

?
1
2
3
4
5
6
7
8
9
10
11
12
// mã ví dụ
riêng tư hàm takeSnapshotOfUIWebView() {
  self.uiWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
   // xử lý hình ảnh
  }
}
 
riêng tư hàm takeSnapshotOfWKWebView() {
  self.wkWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
   // xử lý hình ảnh
  }
}

Giải pháp mới để tạo ảnh chụp màn hình dài bằng WebView.

Ngoài Phương án 1 và Phương án 2, còn có phương án nào mới không?

Câu trả lời là có và chắc chắn.

Điểm mấu chốt của giải pháp mới này là: chức năng in WebView của hệ thống iOS.

Hệ thống iOS hỗ trợ in nội dung WebView sang file PDF. Với tính năng này, thiết kế của giải pháp mới như sau:

  • In tất cả nội dung của thành phần WebView sang một trang PDF
  • Chuyển đổi PDF sang hình ảnh

Mã cốt lõi của giải pháp mới như sau:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import UIKit
nhập WebKit
 
/// WebViewPrintPageRenderer: dùng để in toàn bộ nội dung của webview thành một hình ảnh
cuối cùng nội bộ lớp học WebViewPrintPageRenderer: UIPrintPageRenderer {
 
  riêng tư định dạng var: UIPrintFormatter
 
  riêng tư nội dung varKích thước: CGSize
 
  /// Tạo phiên bản PrintPageRenderer
  ///
  /// - Tham số:
  /// - formatter: WebView của viewPrintFormatter
  /// - contentSize: Kích thước ContentSize của WebView
  bắt buộc init(formatter: UIPrintFormatter, contentSize: CGSize) {
   self.formatter = trình định dạng
   self.contentSize = kích thước nội dung
   siêu.init()
   self.addPrintFormatter(trình định dạng, startingAtPageAt: 0)
  }
 
  ghi đè var paperRect: CGRect {
   trở lại CGRect.init(nguồn gốc: .zero, kích thước: contentSize)
  }
 
  ghi đè var printableRect: CGRect {
   trở lại CGRect.init(nguồn gốc: .zero, kích thước: contentSize)
  }
 
  riêng tư hàm printContentToPDFPage() -> CGPDFPage? {
   hãy để dữ liệu = NSMutableData()
   UIGraphicsBeginPDFContextToData(dữ liệu, self.paperRect, nil)
   self.prepare(for DrawPages: NSMakeRange(0, 1))
   hãy để bounds = UIGraphicsGetPDFContextBounds()
   UIGraphicsBeginPDFPage()
   self.drawPage(tại: 0, trong: giới hạn)
   UIGraphicsEndPDFContext()
 
   hãy để cfData = dữ liệu như CFData
   bảo vệ cho phép nhà cung cấp = CGDataProvider.init(dữ liệu: cfData) khác {
    trở lại không
   }
   hãy để pdfDocument = CGPDFDocument.init(nhà cung cấp)
   hãy để pdfPage = pdfDocument?.page(at: 1)
 
   trở lại Trang pdf
  }
 
  riêng tư hàm covertPDFPageToImage(_ pdfPage: CGPDFPage) -> UIImage? {
   hãy để pageRect = pdfPage.getBoxRect(.trimBox)
   hãy để contentSize = CGSize.init(chiều rộng: sàn nhà (pageRect.size.width), chiều cao: sàn nhà (pageRect.size.height))
 
   // thông thường bạn muốn tham số cuối cùng của UIGraphicsBeginImageContextWithOptions là 0.0 vì điều này sẽ sử dụng tỷ lệ của thiết bị
   UIGraphicsBeginImageContextWithOptions(contentSize, ĐÚNG VẬY , 2.0)
   bảo vệ cho ngữ cảnh = UIGraphicsGetCurrentContext() khác {
    trở lại không
   }
 
   ngữ cảnh.setFillColor(UIColor.white.cgColor)
   bối cảnh.setStrokeColor(UIColor.white.cgColor)
   ngữ cảnh.fill(pageRect)
 
   ngữ cảnh.saveGState()
   ngữ cảnh.translateBy(x: 0, y: contentSize.height)
   ngữ cảnh.scaleBy(x: 1.0, y: -1.0)
 
   context.interpolationQuality = .low
   ngữ cảnh.setRenderingIntent(.defaultIntent)
   ngữ cảnh. drawPDFPage(pdfPage)
   ngữ cảnh.restoreGState()
 
   hãy để hình ảnh = UIGraphicsGetImageFromCurrentImageContext()
   UIGraphicsEndImageContext()
 
   trở lại hình ảnh
  }
 
  /// in toàn bộ nội dung của webview vào một hình ảnh
  ///
  /// - Quan trọng: nếu kích thước của nội dung rất lớn, thì kích thước của hình ảnh cũng sẽ rất lớn
  /// - Trả về: UIImage?
  hàm nội bộ printContentToImage() -> UIImage? {
   bảo vệ cho pdfPage = self.printContentToPDFPage() khác {
    trở lại không
   }
 
   hãy để hình ảnh = self.covertPDFPageToImage(pdfPage)
   trở lại hình ảnh
  }
}
 
phần mở rộng UIWebView {
  công cộng func takeScreenshotOfFullContent(_ hoàn thành: @escaping ((UIImage?) -> Void)) {
   self.scrollView.setContentOffset(CGPoint(x: 0, y: 0), hoạt hình: SAI )
   DispatchQueue.main.asyncAfter(hạn chót: DispatchTime.now() + 0,3) {
    hãy để renderer = WebViewPrintPageRenderer.init(formatter: self.viewPrintFormatter(), contentSize: self.scrollView.contentSize)
    hãy để hình ảnh = renderer.printContentToImage()
    hoàn thành(hình ảnh)
   }
  }
}
 
phần mở rộng WKWebView {
  công cộng func takeScreenshotOfFullContent(_ hoàn thành: @escaping ((UIImage?) -> Void)) {
   self.scrollView.setContentOffset(CGPoint(x: 0, y: 0), hoạt hình: SAI )
   DispatchQueue.main.asyncAfter(hạn chót: DispatchTime.now() + 0,3) {
    hãy để renderer = WebViewPrintPageRenderer.init(formatter: self.viewPrintFormatter(), contentSize: self.scrollView.contentSize)
    hãy để hình ảnh = renderer.printContentToImage()
    hoàn thành(hình ảnh)
   }
  }
}

WebViewPrintPageRenderer là lớp cốt lõi của giải pháp này, chịu trách nhiệm in nội dung của thành phần WebView sang PDF, sau đó chuyển đổi PDF thành hình ảnh. UIWebView và WKWebView triển khai các tiện ích mở rộng tương ứng.

Mã kiểm tra:

?
1
2
3
4
5
6
7
8
9
10
11
12
// mã ví dụ
riêng tư hàm takeSnapshotOfUIWebView() {
  self.uiWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
   // xử lý hình ảnh
  }
}
 
riêng tư hàm takeSnapshotOfWKWebView() {
  self.wkWebView.scrollView.takeScreenshotOfFullContent { (hình ảnh) trong
   // xử lý hình ảnh
  }
}

So sánh ưu nhược điểm của ba giải pháp kỹ thuật.

Vậy, ưu nhược điểm của từng giải pháp kỹ thuật trong 3 giải pháp này là gì và phù hợp với những kịch bản nào?

Giải pháp 1: Chỉ áp dụng cho UIWebView; nếu trang web chứa nhiều nội dung, nó sẽ chiếm quá nhiều bộ nhớ khi tạo ảnh chụp màn hình dài. Vì vậy, giải pháp này chỉ phù hợp với những tình huống không cần hỗ trợ WKWebView và nội dung trang web không có quá nhiều nội dung.

Tùy chọn 2: Áp dụng cho UIWebView và WKWebView và đặc biệt phù hợp với WKWebView. Nhờ cơ chế phân trang để tạo ảnh chụp màn hình, việc sử dụng bộ nhớ sẽ giảm đi một cách hiệu quả. Tuy nhiên, có một vấn đề với giải pháp này: nếu trang web có phần tử location: cố định (chẳng hạn như thanh điều hướng cố định ở đầu trang web), phần tử đó sẽ xuất hiện lặp lại trên hình ảnh dài được tạo ra.

方案三:适用 UIWebView 和 WKWebView。其中最重要的一步——“把WebView内容打印到PDF” 是由iOS系统实现,所以该方案的性能在理论上是可以得到保障的。不过,这个方案存在一个问题:在把网页内容打印到PDF时,iOS系统获取的 contentSize 比WebView的实际contentSize 要大,从而导致生成的图片在靠近底部的内容部分和实际存在一点差异。具体可以下载运行我的长截图库 SnapshotKit 的 Demo,通过其中的 UIWebView 和 WKWebView 截图示例查看具体截图效果.

以上三个方案,总的来说,解决了部分场景的需求,但都不够完美,仍需做进一步的优化.

Tóm tắt.

Trên đây là toàn bộ nội dung bài viết mong rằng nội dung bài viết có giá trị tham khảo nhất định cho quá trình học tập, làm việc của mọi người. Nếu có thắc mắc gì có thể để lại tin nhắn để trao đổi.

原文链接:https://juejin.im/post/5b9d145ae51d450e7579d1e5 。

最后此篇关于iOS使用WebView生成长截图的第3种解决方案的文章就讲到这里了,如果你想了解更多关于iOS使用WebView生成长截图的第3种解决方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
qq735679552
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress