I’m showing a PDF page in UIView’s subview using PDFKit along with some UILabel and UIImageView. At a time I’m only showing one page in PDFView. Users can change the size and position of this PDFView.
class ResizablePDFView: PDFView {
override func draw(_ rect: CGRect) {
super.draw(rect)
}
override func draw(_ layer: CALayer, in ctx: CGContext) {
let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty
if isPDF {
if let document = self.document, document.pageCount > 0, let page = document.page(at: 0) {
ctx.saveGState()
ctx.scaleBy(x: 1, y: -1)
ctx.translateBy(x: 0, y: -bounds.size.height)
let pageBounds = page.bounds(for: .mediaBox)
ctx.scaleBy( x: bounds.size.width / pageBounds.size.width, y: bounds.size.height / pageBounds.size.height)
ctx.translateBy(x: -pageBounds.origin.x, y: -pageBounds.origin.y)
page.draw(with: .mediaBox, to: ctx)
ctx.restoreGState()
}
}else {
super.draw(layer, in: ctx)
}
}
}
class ResizableLabelView: UILabel {
func setup() {
self.font = UIFont.systemFont(ofSize: 20)
self.textColor = UIColor.systemBlue
}
override func draw(_ rect: CGRect) {
super.draw(rect)
}
override func draw(_ layer: CALayer, in ctx: CGContext) {
let isPDF = !UIGraphicsGetPDFContextBounds().isEmpty
if isPDF {
draw(bounds)
}else {
super.draw(layer, in: ctx)
}
}
}
CanvasView setup,
class ViewController: UIViewController {
var canvasView: UIView!
var pdfView: ResizablePDFView!
var label: ResizableLabelView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.gray
self.canvasView = UIView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 400, height: 573)))
self.canvasView.center = self.view.center
self.canvasView.backgroundColor = UIColor.white
self.view.addSubview(self.canvasView)
self.setupPDF()
self.setupLabel()
}
func setupPDF() {
self.pdfView = ResizablePDFView(frame: CGRect(origin: .zero, size: self.canvasView.frame.size))
self.pdfView.backgroundColor = UIColor.clear
self.canvasView.addSubview(self.pdfView)
self.pdfView.autoScales = false
self.pdfView.displayMode = .singlePage
self.pdfView.displaysPageBreaks = false
self.pdfView.pageBreakMargins = UIEdgeInsets.zero
self.pdfView.pageShadowsEnabled = false
if let file = Bundle.main.url(forResource: "sample_pdf", withExtension: "pdf") {
if let pdfDocument = PDFDocument(url: file) {
let pageNumber: Int = 0
if let page = pdfDocument.page(at: pageNumber) {
let pageDocument = PDFDocument()
pageDocument.insert(page, at: 0)
self.pdfView.document = pageDocument
self.pdfView.minScaleFactor = self.pdfView.scaleFactorForSizeToFit
self.pdfView.maxScaleFactor = self.pdfView.scaleFactorForSizeToFit
self.pdfView.scaleFactor = self.pdfView.scaleFactorForSizeToFit
}
}
}
}
func setupLabel() {
self.label = ResizableLabelView(frame: CGRect(x: 10, y: 10, width: 200, height: 50))
self.label.setup()
self.label.text = "Sample Text"
self.label.sizeToFit()
self.canvasView.addSubview(self.label)
}
}
now, I'm creating the PDF from canvasView
@IBAction func exportButtonAction(_ sender: UIButton) {
let filePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("Exported_PDF.pdf")
UIGraphicsBeginPDFContextToFile(filePath.path, .zero, [kCGPDFContextCreator as String: "PDF Export Demo App"])
guard let canvas = self.canvasView else { return }
UIGraphicsBeginPDFPageWithInfo(canvas.bounds, nil)
guard let context = UIGraphicsGetCurrentContext() else { return }
canvas.setNeedsDisplay()
canvas.layer.render(in: context)
UIGraphicsEndPDFContext()
print(filePath)
}
Now, This will render UILabel and UIImageView in PDF properly without rasterization and selectable text, but It does not draw PDFView like original pdf with links. What am I doing wrong here? how can I debug this issue?
https://drive.google.com/drive/folders/1qLcGNGWxoXbWJnr6xBxueKjPHnfxYS6D?usp=drive_link