PDFPageRenderable.swift 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. //
  2. // PDFPageRenderable.swift
  3. // PDFGenerator
  4. //
  5. // Created by Suguru Kishimoto on 2016/02/10.
  6. //
  7. //
  8. import Foundation
  9. import UIKit
  10. import WebKit
  11. protocol PDFPageRenderable {
  12. func renderPDFPage(scaleFactor: CGFloat) throws
  13. }
  14. private extension UIScrollView {
  15. typealias TempInfo = (frame: CGRect, offset: CGPoint, inset: UIEdgeInsets)
  16. var tempInfo: TempInfo {
  17. return (frame, contentOffset, contentInset)
  18. }
  19. func transformForRender() {
  20. contentOffset = .zero
  21. contentInset = UIEdgeInsets.zero
  22. frame = CGRect(origin: .zero, size: contentSize)
  23. }
  24. func restore(_ info: TempInfo) {
  25. frame = info.frame
  26. contentOffset = info.offset
  27. contentInset = info.inset
  28. }
  29. }
  30. extension UIView: PDFPageRenderable {
  31. fileprivate func _render<T: UIView>(_ view: T, scaleFactor: CGFloat, completion: (T) -> Void = { _ in }) throws {
  32. guard scaleFactor > 0.0 else {
  33. throw PDFGenerateError.invalidScaleFactor
  34. }
  35. let size = getPageSize()
  36. guard size.width > 0 && size.height > 0 else {
  37. throw PDFGenerateError.zeroSizeView(self)
  38. }
  39. guard let context = UIGraphicsGetCurrentContext() else {
  40. throw PDFGenerateError.invalidContext
  41. }
  42. let renderFrame = CGRect(origin: .zero, size: CGSize(width: size.width * scaleFactor, height: size.height * scaleFactor))
  43. autoreleasepool {
  44. let superView = view.superview
  45. view.removeFromSuperview()
  46. UIGraphicsBeginPDFPageWithInfo(renderFrame, nil)
  47. view.layer.render(in: context)
  48. superView?.addSubview(view)
  49. superView?.layoutIfNeeded()
  50. completion(view)
  51. }
  52. }
  53. func renderPDFPage(scaleFactor: CGFloat) throws {
  54. func renderScrollView(_ scrollView: UIScrollView) throws {
  55. let tmp = scrollView.tempInfo
  56. scrollView.transformForRender()
  57. try _render(scrollView, scaleFactor: scaleFactor) { scrollView in
  58. scrollView.restore(tmp)
  59. }
  60. }
  61. if let webView = self as? UIWebView {
  62. try renderScrollView(webView.scrollView)
  63. } else if let webView = self as? WKWebView {
  64. try renderScrollView(webView.scrollView)
  65. } else if let scrollView = self as? UIScrollView {
  66. try renderScrollView(scrollView)
  67. } else {
  68. try _render(self, scaleFactor: scaleFactor)
  69. }
  70. }
  71. fileprivate func getPageSize() -> CGSize {
  72. switch self {
  73. case (let webView as UIWebView):
  74. return webView.scrollView.contentSize
  75. case (let webView as WKWebView):
  76. return webView.scrollView.contentSize
  77. case (let scrollView as UIScrollView):
  78. return scrollView.contentSize
  79. default:
  80. return self.frame.size
  81. }
  82. }
  83. }
  84. extension UIImage: PDFPageRenderable {
  85. func renderPDFPage(scaleFactor: CGFloat) throws {
  86. guard scaleFactor > 0.0 else {
  87. throw PDFGenerateError.invalidScaleFactor
  88. }
  89. autoreleasepool {
  90. let bounds = CGRect(
  91. origin: .zero,
  92. size: CGSize(
  93. width: size.width * scaleFactor,
  94. height: size.height * scaleFactor
  95. )
  96. )
  97. UIGraphicsBeginPDFPageWithInfo(bounds, nil)
  98. draw(in: bounds)
  99. }
  100. }
  101. }
  102. protocol UIImageConvertible {
  103. func asUIImage() throws -> UIImage
  104. }
  105. extension UIImage: UIImageConvertible {
  106. func asUIImage() throws -> UIImage {
  107. return self
  108. }
  109. }
  110. extension String: UIImageConvertible {
  111. func asUIImage() throws -> UIImage {
  112. guard let image = UIImage(contentsOfFile: self) else{
  113. throw PDFGenerateError.imageLoadFailed(self)
  114. }
  115. return image
  116. }
  117. }
  118. extension Data: UIImageConvertible {
  119. func asUIImage() throws -> UIImage {
  120. guard let image = UIImage(data: self) else {
  121. throw PDFGenerateError.imageLoadFailed(self)
  122. }
  123. return image
  124. }
  125. }
  126. extension CGImage: UIImageConvertible {
  127. func asUIImage() throws -> UIImage {
  128. return UIImage(cgImage: self)
  129. }
  130. }