Posts

Post not yet marked as solved
0 Replies
706 Views
I have been trying to find a way to export a View in SWIFTUI in A4 size pages PDF. The view cannot fit in one single page. So far I have managed to edit (with the help of ChatGPT) the code found in PDF Creator GitHub (See below) But although I get multiple page PDF as a result only the first page is populated, the rest are just blank. Does anyone faced something similar before, if yes how did you manage to export to PDF in A4 pages... Thanks for any tips and help! extension View{ func sharePDF<Content: View> (@ViewBuilder content: @escaping () -> Content, fileName: String) { exportPDF(content: content, completion: { status , url in if let url = url, status { ShareSheet.instance.share(items: [url]) } else { print("⚠️ Failed to make PDF") } }, fileName: fileName) } // MARK: Extracting View's Height and width with the Help of Hosting Controller and ScrollView fileprivate func convertToScrollView<Content: View>(@ViewBuilder content: @escaping ()->Content)->UIScrollView{ let scrollView = UIScrollView() // MARK: Converting SwiftUI View to UIKit View let hostingController = UIHostingController(rootView: content()).view! hostingController.translatesAutoresizingMaskIntoConstraints = false // MARK: Constraints let constraints = [ hostingController.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), hostingController.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), hostingController.topAnchor.constraint(equalTo: scrollView.topAnchor), hostingController.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), // Width Anchor hostingController.widthAnchor.constraint(equalToConstant: screenBounds().width) ] scrollView.addSubview(hostingController) scrollView.addConstraints(constraints) scrollView.layoutIfNeeded() return scrollView } // MARK: Export to PDF // MARK: Completion Handler will Send Status and URL fileprivate func exportPDF<Content: View>(@ViewBuilder content: @escaping () -> Content, completion: @escaping (Bool, URL?) -> (), fileName: String) { // MARK: Temp URL let documentDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! // MARK: To Generate New File whenever it's generated let outputFileURL = documentDirectory.appendingPathComponent("\(fileName)\(UUID().uuidString).pdf") // MARK: PDF View let scrollView = convertToScrollView { content() } scrollView.tag = 1009 scrollView.frame = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4 size in points (72 points per inch) let pageSize = scrollView.frame.size let contentSize = scrollView.contentSize let pageCount = Int(ceil(contentSize.height / pageSize.height)) // Create PDF Context UIGraphicsBeginPDFContextToFile(outputFileURL.path, .zero, nil) // CHATGPT: for index in 0..<pageCount { // Begin new PDF page UIGraphicsBeginPDFPageWithInfo(CGRect(origin: .zero, size: pageSize), nil) // Calculate the visible frame for each page let visibleFrame = CGRect(x: 0, y: -pageSize.height * CGFloat(index), width: pageSize.width, height: pageSize.height) // Capture the screenshot of the visible content synchronously scrollView.clipToRect(visibleFrame) { // Take a screenshot of the visible content let screenshot = scrollView.takeScreenshot() // Draw the screenshot into the PDF context screenshot.draw(at: .zero) } } completion(true, outputFileURL) // End PDF Context UIGraphicsEndPDFContext() completion(true, outputFileURL) // Removing the added View getRootController().view.subviews.forEach { view in if view.tag == 1009 { print("Removed") view.removeFromSuperview() } } } fileprivate func screenBounds()->CGRect{ return UIScreen.main.bounds } fileprivate func getRootController()->UIViewController{ guard let screen = UIApplication.shared.connectedScenes.first as? UIWindowScene else{ return .init() } guard let root = screen.windows.first?.rootViewController else{ return .init() } return root } fileprivate func getSafeArea()->UIEdgeInsets{ guard let screen = UIApplication.shared.connectedScenes.first as? UIWindowScene else{ return .zero } guard let safeArea = screen.windows.first?.safeAreaInsets else{ return .zero } return safeArea } } extension UIView { func takeScreenshot() -> UIImage { UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale) drawHierarchy(in: bounds, afterScreenUpdates: true) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image ?? UIImage() } func clipToRect(_ rect: CGRect, perform: () -> Void) { guard let context = UIGraphicsGetCurrentContext() else { return } context.saveGState() context.clip(to: rect) perform() context.restoreGState() } }
Posted
by IFA.
Last updated
.