Display and manipulate PDF documents in your applications using PDFKit.

Posts under PDFKit tag

69 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Create a PDF-File of a view with correct papersize
Hello together, does anyone know how I can scale a view to a given document size (e.g. A4: 210/297 mm) without scaling the view itself? With enclosed code I can create the pdf-document, but the paperize is not the intended size. It is too big. Variation this line of code var mediaBox = CGRect(origin: .zero, size: CGSize(width: size.width, height: size.height)) into var mediaBox = CGRect(origin: .zero, size: CGSize(width: 595, height: 842) does not scale the view (it just shows a part of it at the correct papersize). So what do I have to do to scale the rendered view to the proper size? Enclosed a very simple code snipped to see th strange behavior. Thx, best regards Peter import SwiftUI struct ContentView: View { var body: some View { ZStack { Rectangle() .frame(width: 2100, height: 2910) .foregroundColor(.red) Rectangle() .frame(width: 2100/2, height: 2910/3) .foregroundColor(.blue) Text("Hello, world!") } .padding() .onAppear(perform: { generatePDF() }) } // generate pdf from given view @MainActor func generatePDF() -> URL { // Select UI View to render as pdf let image = ImageRenderer(content: ContentView()) let url = URL.documentsDirectory.appending(path: "generatedPDF.pdf") image.render{ size, context in var mediaBox = CGRect(origin: .zero, size: CGSize(width: size.width, height: size.height)) guard let consumer = CGDataConsumer(url: url as CFURL), let pdfContext = CGContext(consumer: consumer, mediaBox: &mediaBox, nil) else { return } pdfContext.beginPDFPage(nil) pdfContext.translateBy(x: mediaBox.size.width / 2 - size.width / 2, y: mediaBox.size.height / 2 - size.height / 2) context(pdfContext) pdfContext.endPDFPage() pdfContext.closePDF() } print("Saving PDF to \(url.path())") return url } } #Preview { ContentView() } ![]("https://developer.apple.com/forums/content/attachment/67b11ec8-af9e-4ab7-a0a5-0c020b7a45d4" "title=generatedPDF (without scaling).jpg;width=2652;height=2526") ![]("https://developer.apple.com/forums/content/attachment/b2c24a25-3805-4664-8adb-dcb81c3e96c4" "title=generatedPDF (with scaling).jpg;width=2132;height=1510")
1
0
444
Mar ’24
Render custom PDFView in PDF with swift
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
0
0
425
Mar ’24
How to prepare PDF for digital certificate on iOS
I'm looking for guidance on how to prepare a PDF for inserting a digital certificate on iOS without a commercial 3rd party tool. The idea is to... Set up a signature annotation with PDFKit, Set up/prepare the PDF with the required information (contact info, adbe.pkcs7.detached, the Adobe.PPKLite filter , info/annotation reference, the UTC time, etc.) Pad the content area with zeros (I believe it would 4096 Then compute the hash. I am following Adobe's Spec (Acrobat_DigitalSignatures_in_PDF) Would this be possible with parsing out and adding the data from a byte stream? Can I simply build the signature object on my own and place them into the PDF, or are there any other items I need to change. Are there any tools out there that can help me manipulate the data and/or get the document hash easily? For example the data would look something like this is... <</ByteRange [0 552215 560537 907] /ContactInfo (my contact info)/Contents < AREA OF ZERO PADDING FOR CERT INSET) 00>/Filter /Adobe.PPKLite/M (D:20240223095734Z)/Reason (Some reason)/Reference [<</Data 13 0 R/TransformMethod/FieldMDP/TransformParams 39 0 R/Type/SigRef>>]/SubFilter /adbe.pkcs7.detached/Type /Sig>> Thank you
0
0
368
Feb ’24
PDFPage setBounds behaviour on cropBox differs on iPhone and iPad
I am trying to crop a pdf to remove 100 points from the top and bottom of the page. The mediaBounds of my pdf is size 612x792 and the origin is 0,0. My code the set the bounds of the cropBox is: page.setBounds(CGRect(origin: CGPointMake(0,100), size: CGSize(width: 612, height: 592)), for: .cropBox) This sets the origin at 0,100 and the cropBox size to be 200 less than the mediaBox size. This works on iPhone, but on iPad I need to set the height to be 692, otherwise too much is cropped. Is this a bug or is there an explanation?
0
0
313
Feb ’24
App running on iOS 17 creates different PDF data from on iOS 16 and earlier
Hello, I have a question about PDF data creation on iOS 17. My app creates PDF data from HTML for printing, and it is not possible to print out the PDF data to a particular printer when the app runs on iOS 17, despite that it works fine on iOS 16 and earlier. The cause of the printing problem is unclear, however, I found that the contents of PDF data are different between iOS 17 and iOS 16 in the following 4 points: PDF version iOS 17: Ver. 1.4 iOS 16: Ver. 1.3 Size of PDF data iOS 17: 100KB iOS 16: 505KB Embedded font iOS 17: HiraginoSans-W5 iOS 16: HiraginoSans-W3 Displayed text size iOS 17: just a little bigger than 14pt iOS 16: 14pt I am hoping that the printing problem can be resolved if my app running on iOS 17 creates the same PDF data as on iOS 16, so my question is: Is there any way to create the same format of PDF data as iOS 16 or earlier when an app is running on iOS 17, especially to create data in version 1.3 of PDF? In my app, I use almost the same as the following code to create PDF data from HTML, and I couldn't find any option to specify a version of PDF for UIPrintPageRenderer, UIMarkupTextPrintFormatter and UIGraphicsPDFContext classes... Any info would be appreciated. Thanks, let htmlString = """ <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=420,height=595, shrink-to-fit=yes" /> <style type="text/css"> * { box-sizing: border-box; font-family: 'Hiragino Mincho ProN', serif; font-size: 1em; line-height: 1; } body { margin: 0; padding: 0; font-size: 14pt; } span.gothic { font-size: 3.5em; font-family: "Helvetica Neue", Helvetica, "Hiragino Sans", sans-serif; } </style> </head> <body> 明朝体のテキスト <span class="gothic">ゴシック体のテキスト</span> </body> </html> """ let render = UIPrintPageRenderer() let paperRect = CGRect(x: 0, y: 0, width: 420.0, height: 595) // A5, 72 dpi render.setValue(paperRect, forKey: "paperRect") let contentsRect = CGRect(x: 0, y: 0, width: 420.0, height: 595) // A5, 72 dpi render.setValue(contentsRect, forKey: "printableRect") let fmt = UIMarkupTextPrintFormatter(markupText: htmlString) render.addPrintFormatter(fmt, startingAtPageAt: 0) let pdfData = NSMutableData() UIGraphicsBeginPDFContextToData(pdfData, paperRect, nil) render.prepare(forDrawingPages: NSMakeRange(0, render.numberOfPages)) let bound = UIGraphicsGetPDFContextBounds() for i in 0..<render.numberOfPages { UIGraphicsBeginPDFPage() render.drawPage(at: i, in: bound) } UIGraphicsEndPDFContext() do { let url = URL(fileURLWithPath:"test.pdf") try pdfData.write(to: url) print("Done") } catch { print("Failed to save", error) }
0
0
404
Feb ’24
Does UIGraphicsEndPDFContext flush and close the context file?
I'm getting infrequent crashes when I try to show a newly created PDF. The PDF is file based, and shortly after UIGraphicsEndPDFContext its shown. The crash reports make it appear that the file itself is being mutated after its displayed. So my question: is the file (self.filePath) absolutely flushed and closed when UIGraphicsEndPDFContext returns? If not, is there some way to detect when it has finished? Thanks! David `func addPageNumbers() { let url = URL(fileURLWithPath: filePath) guard let document = CGPDFDocument(url as CFURL) else { return } // You have to change the file path otherwise it can cause blank white pages to be drawn. self.filePath = "\(filePath)-final.pdf" UIGraphicsBeginPDFContextToFile(filePath, .zero, nil) let pageCount = document.numberOfPages for i in 1...pageCount { ... } } UIGraphicsEndPDFContext() }
1
0
412
Jan ’24
PDFView highlight button doing nothing & can't override
Hi everyone, I'm trying to make a custom highlight functionality in PDFKit's PDFView on iOS 16. I've tried everything recommended online, and it seems like there's no way to fully override the menu and remove the normal "Highlight" action which actually does nothing if you tap it. I'd be okay with being able to either remove the base Highlight action because I'm able to add my own, or figure out how to handle a tap on that button. Here's what I've tried, and the result: override func buildMenu(with builder: UIMenuBuilder) { super.buildMenu(with: builder) builder.remove(menu: .application) builder.remove(menu: .lookup) builder.remove(menu: .learn) builder.remove(menu: .find) builder.remove(menu: .file) builder.remove(menu: .edit) builder.remove(menu: .services) if #available(iOS 16.0, *) { builder.remove(menu: .document) } let highlightAction = UIAction(title: "Highlight 2", attributes: []) { _ in print("This works") } } let highlightMenu = UIMenu(title: "Highlight 2", options: [.displayInline], children: [highlightAction]) builder.remove(menu: .standardEdit) builder.remove(menu: .share) builder.remove(menu: .toolbar) builder.remove(menu: .text) builder.remove(menu: .font) builder.remove(menu: .format) builder.remove(menu: .transformations) builder.remove(menu: .preferences) builder.remove(menu: .window) builder.remove(menu: .view) builder.replaceChildren(ofMenu: .root, from: { _ in [highlightAction] }) } Please help!
1
0
433
Jan ’24
wwdc2022-10089 and various issues
Hi, I encounter various problems with inserting PKDrawing into a PDFAnnotation : First : After "page.addAnnotation(myCustomAnnotation)", saved document seems corrupted (affected pages are displayed with a "X" watermark covering the whole page), Second : The only way to extract PKDrawing from the annotation is unarchiveTopLevelObjectWithData: which is deprecated, Final : I'm not able to re-read PKDrawings to restore PKCanvasView undoManager. Does anyone have an idea on a correct way to do this? Thank you in advance and happy new year everyone!
0
0
424
Jan ’24
PDFKit is not working in MacOs
I am creating a PDF document with the information from the database. For iOS I have it working completely, but for macOs I can't get it to work no matter what I try. I now have this code: func generateRentalPDF(_ invoiceModel: InvoiceModel, _ customerInfo: CustomerModel, _ completion: @escaping (Data?) -> Void) { guard let baseDocument = loadBasePDF(), let page = baseDocument.page(at: 0) else { completion(nil) return } var pageBounds = page.bounds(for: .mediaBox) let pdfData = NSMutableData() guard let dataConsumer = CGDataConsumer(data: pdfData as CFMutableData), let pdfContext = CGContext(consumer: dataConsumer, mediaBox: &pageBounds, nil) else { completion(nil) return } pdfContext.beginPDFPage(nil) if let cgPage = page.pageRef { pdfContext.drawPDFPage(cgPage) } // Set text attributes let textString = "Invoice Number: \(invoiceModel.invoiceNumber)" let textStyle = NSMutableParagraphStyle() textStyle.alignment = .left let textAttributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(orSize: 18), .foregroundColor: NSColor.black, .paragraphStyle: textStyle ] // Calculate text position let textRect = CGRect(x: 100, y: pageBounds.height - 150, width: 300, height: 50) // Draw the text pdfContext.saveGState() pdfContext.translateBy(x: 0, y: pageBounds.height) pdfContext.scaleBy(x: 1.0, y: -1.0) let attributedText = NSAttributedString(string: textString, attributes: textAttributes) attributedText.draw(in: textRect) pdfContext.restoreGState() pdfContext.endPDFPage() pdfContext.closePDF() completion(pdfData as Data) } When I open the document in the app, I do see the base document. Even if I put a stroke around the text, I also see the stroke. However, the text does not appear on the screen. What am I overlooking or what am I doing wrong? I hope someone here has an answer for me, thank you very much in advance.
1
0
362
Dec ’23
iOS/iPadOS 17.2 Bug in PDFKit duplicates content of filled PDF form fields
The following situation is given: In your code you have a PDFDocument object. This contains a PDF file with form fields that are filled with text. If you call the dataRepresentation() method on this PDFDocument object, you get back a data object: let myDocumentData: Data = pdfDocument.dataRepresentation()! If you now want to initialize a new PDFDocument object with this data object, the contents of the form fields are duplicated within the PDF. let newPDF: PDFDocument = PDFDocument(data: myDocumentData) If you now want to print the newPDF PDFDocument object by creating a new print job, you will get the following result: What you actually expect to see: You only see this behavior when you want to print or share the PDF. You won't see this behaviour inside a PDF View in your application. This behaviour only appears since iOS/iPadOS 17.2 Steps to reproduce: Get a PDF file with form fields, especially text fields fill out these text fields with text create a PDFDocument object with this PDF file call the dataRepresentation() method on this PDFDocument object and store the result in a new variable create a new PDFDocument object with the data object created in the previous step:PDFDocument(data: <data>) Print the new created PDFDocument within iOS/iPadOS 17.2 or share it for example via email I hope Apple will fix this bug soon!
5
4
901
Dec ’23
Create PDF file with Spot Colors
I am trying to generate a PDF file with certain components draw with Spot Colours. Spot colours are used for printing and I am not clear on how one would do that but I think that if I can create a custom ColorSpace with a specific name or a color that has a specific name - our printer looks for the name Spot1 and they use the colour green. Can anyone shed any light on how I might be able to do this. For reference I have attached two pdf files with two different spot colours in them. I need to be able to create similar using CGContext and CGPDFDocument. I can already generate the PDF documents using CMYK colors but don't know how I can create the equivalent "spot" colors. At the moment I am loading the page from these attached pdf files and scaling them to fill the page to get a background with the spot color. This works fine but I also need to generate text and lines using this same spot color and I am not clear how I could do that using the Core Graphics APIs. My guess is I need to create a custom ColorSpace with a single color and then use that color for drawing with. The only 'custom' option for creating a ColorSpace seems to be the CGColorSpace(propertyListPList:) constructor, however there does not appear to be any documentation on what needs to be in the property list to do so. Nor can I find any examples of that. Any pointers would be appreciated. Regards
1
0
554
Dec ’23
ios17 breaks custom page size for PDF export
We have an app that exports PDFs with a custom page size, using PSDKit. In iOS16 the PDF export would have the correct page size dimensions, but now iOS17 exports everything to a Letter (8.5x11) size, regardless of what the PDF size specs are defined in the code: let pageWidth: CGFloat = 86.0 / 25.4 * 72 let pageHeight: CGFloat = 54.0 / 25.4 * 72 let pageSize = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight) Any thoughts as to how to fix this?
3
0
679
Dec ’23
PDFKit on macOS. Nearest page & converting point to document point not working.
On macOS page(for: viewPoint, nearest: false) returns the wrong page. If I enter a coordinate on page 1 less than 1/3 of the way down, it returns that it is on page 0. Likewise on page 2 it will say page 1 anywhere in the top third. Also PDFView's convert(point, to: page) will return seemingly random values for the document point's y value, but in the expected range of 0 to about 792 (for an 11" page at 72dpi). Displaying the document horizontal/vertical doesn't matter. The x value of the point is always correct and everything works correctly on iOS. I've tried Xcode 15.0 and 15.1 beta 3. Anyone using these functions correctly, or seeing the same issue?
0
0
337
Dec ’23
Why does it not exist via @AppStorage
2 versions 1 works 1 doesn't. UIViewRepresentable to show a PDF @AppStorage(DefaultsKey.userActiveBook.rawValue) var activeBook : URL = Bundle.main.url(forResource: "BookPlaceHolder", withExtension: "pdf")! func makeUIView(context: Context) -&gt; PDFView { do { let pdfData = try Data(contentsOf: activeBook) pdfView.document = PDFDocument(data: pdfData) //&lt;---- is nil ... } catch let Error { print(Error) } } fails with Error Domain=NSCocoaErrorDomain Code=260 "The file “BookPlaceHolder.pdf” couldn’t be opened because there is no such file." func makeUIView(context: Context) -&gt; PDFView { do { let pdfData = try Data(contentsOf: Bundle.main.url(forResource: "BookPlaceHolder", withExtension: "pdf")!) pdfView.document = PDFDocument(data: pdfData) ... } catch let Error { print(Error) } } Works perfectly. What is it with using @AppStorage to access the exact same URL causing the discrepancies ?
2
0
530
Dec ’23
How to set the Anchors Points of a PDF in PDFKit?
I am trying to set the top anchor point of a pdf that is inside of a view with the .ignoresSafeArea() modifier. I would also like it to work on the edges when the phone is in landscape although for simplicity I will only explain what I want for the top. I want it to function like the iOS Files app pdf viewer where when tapped it hides the navigation bars but the top of the pdf stays at the same place, but when you zoom in on the pdf it can fill the whole screen. When you zoom back out the top should return to the same place as before. Here is a simple view to show how it is being used: @MainActor struct ContentView: View { @State var showBars: Bool = true @State var pdfUrl: URL? var body: some View { NavigationStack { GeometryReader { geo in ScrollView { TabView { if let url = pdfUrl { PDFViewer(pdfUrl: url) .onTapGesture { withAnimation { showBars.toggle() } } } } .tabViewStyle(.page(indexDisplayMode: .never)) .frame(width: geo.size.width, height: geo.size.height) } .scrollDisabled(true) } .ignoresSafeArea(edges: !showBars ? .all : []) } .task { pdfUrl = renderPDF() } } func renderPDF() -> URL { let renderer = ImageRenderer(content: VStack {}) let url = URL.documentsDirectory.appending(path: "samplepdf.pdf") renderer.render { size, context in guard let pdf = CGContext(url as CFURL, mediaBox: nil, nil) else { return } pdf.beginPDFPage(nil) context(pdf) pdf.endPDFPage() pdf.beginPDFPage(nil) context(pdf) pdf.endPDFPage() pdf.closePDF() } return url } } And here is what my pdfView looks like so far: struct PDFViewer: View { var pdfUrl: URL var body: some View { PDFSheetView(document: .init(url: pdfUrl)) } } class PDFViewController: UIViewController { let document: PDFDocument? var pdfView: PDFView! init(document: PDFDocument?) { self.document = document super.init(nibName: nil, bundle: nil) } override func loadView() { let view = PDFView() self.view = view self.pdfView = view view.document = document view.displayDirection = .vertical view.autoScales = true view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true } required init?(coder: NSCoder) { document = nil super.init(coder: coder) return nil } override func viewDidLayoutSubviews() { let bounds = view.bounds if let document { if let page = document.page(at: 0) { let pageBounds = page.bounds(for: .mediaBox) if bounds.width > 0 && pageBounds.width > 0 { let scaleFactor = bounds.width / pageBounds.width let subtractionFactor = scaleFactor * 0.0125 pdfView.minScaleFactor = scaleFactor - subtractionFactor } } } } } struct PDFSheetView: UIViewControllerRepresentable { typealias UIViewControllerType = PDFViewController let document: PDFDocument? func makeUIViewController(context: Context) -> PDFViewController { let controller = PDFViewController(document: document) return controller } func updateUIViewController(_ uiViewController: PDFViewController, context: Context) { } } Is this possible to do? Like I said before, I want it to function just like the iOS Files app pdf viewer.
0
0
332
Nov ’23
Problems with PDFKit
How to fix it? Errors: "Cannot find type 'UIViewRepresentable' in scope" "Cannot find type 'Context' in scope" "Cannot find type 'Context' in scope" I tried: Re-installed the Xcode Re-started computer Great thanks. import SwiftUI import PDFKit struct PDFViewerView: UIViewRepresentable { var url: URL func makeUIView(context: Context) -> PDFView { let pdfView = PDFView() pdfView.document = PDFDocument(url: self.url) return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // Update the view. } } Xcode Version 15.0.1 (15A507)
1
0
453
Nov ’23