Created
February 10, 2020 23:16
-
-
Save stevelandeyasana/b50d507a6ba822372fad224ac9639b7d to your computer and use it in GitHub Desktop.
A UIView that renders a PDF page at a given resolution and constrains itself to the PDF page's aspect ratio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Uses Cartography for layout, but you should be able to translate it to NSLayoutConstraint pretty easily | |
import Cartography | |
/// Render a single page of a PDF, non-interactive, at an arbitrary size. | |
/// Adds its own constraint to maintain its correct aspect ratio. | |
class PDFPageView: UIView { | |
var displayBox: PDFDisplayBox = .artBox | |
var majorAxisLength: CGFloat = 2048 | |
var page: PDFPage? { didSet { applyState() } } | |
private let aspectRatioConstrainGroup = ConstraintGroup() | |
convenience init(page: PDFPage?) { | |
self.init(frame: .zero) | |
self.page = page | |
} | |
override init(frame: CGRect) { | |
super.init(frame: frame) | |
} | |
required init?(coder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
private func applyState() { | |
if let page = page { | |
let bounds = page.bounds(for: displayBox) | |
let multiplier = bounds.size.width / bounds.size.height | |
constrain(self, replace: aspectRatioConstrainGroup) { it in | |
it.width == it.height * multiplier | |
} | |
setNeedsDisplay() | |
setNeedsLayout() | |
} else { | |
// no constraints at all (no PDF, so no 'correct' aspect ratio) | |
constrain(self, replace: aspectRatioConstrainGroup) { _ in } | |
} | |
} | |
// MARK: UIView | |
override var intrinsicContentSize: CGSize { | |
if let page = page { | |
let bounds = page.bounds(for: displayBox) | |
if bounds.size.width > bounds.size.height { | |
return CGSize( | |
width: majorAxisLength, | |
height: majorAxisLength * (bounds.size.height / bounds.size.width)) | |
} else { | |
return CGSize( | |
width: majorAxisLength * (bounds.size.width / bounds.size.height), | |
height: majorAxisLength) | |
} | |
} else { | |
return .zero | |
} | |
} | |
override func draw(_ rect: CGRect) { | |
guard let context = UIGraphicsGetCurrentContext(), let page = page else { return } | |
// Render the PDF to the CGContext. | |
// PDF coordinate system is Y-flipped from Core Graphics | |
context.translateBy(x: 0, y: rect.height) | |
// Ask PDF to apply its crop box transform | |
let bounds = page.bounds(for: displayBox) | |
page.transform(context, for: displayBox) | |
// Scale PDF to view size | |
context.scaleBy(x: rect.width / bounds.width, y: -rect.height / bounds.height) | |
// Draw! | |
page.draw(with: displayBox, to: context) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment