I wrote a couple of PDF manipulation handlers in ASObjC to replace the Automator actions that went squirrelly after macOS 12.3 released (python 2 was removed despite these actions still relying on them).
Everything was going smoothly until I tried to figure out how to add text to a PDF using ASObjC. It seems like it should be straightforward, but it’s getting hung up on how to create a CFURL (in Objective-C, these are transparently bridged from NSURL, but AppleScript can’t seem to bridge the value).
From what I understand, I should be able to call a CoreGraphics function from ASObjC…
use scripting additions
use framework "Foundation"
use framework "PDFKit"
use framework "AppKit"
use framework "CoreGraphics"
use framework "CoreFoundation"
use framework "Quartz"
set pdf_path to "/PATH/TO/PDF.pdf"
set file_URL to current application's NSURL's fileURLWithPath:pdf_path
set PDF_document to current application's PDFDocument's alloc()'s initWithURL:file_URL
set temp_out_path to "/PATH/TO/OUT.pdf"
set temp_out_URL to current application's NSURL's fileURLWithPath:temp_out_path
set graphics_context to current application's CGPDFContextCreateWithURL(temp_out_URL, missing value, missing value)
--> Error: CGPDFContextCreateWithURL unable to set argument 0 - the AppleScript value <NSAppleEventDescriptor: 'obj '{ 'form':'ID ', 'want':'ocid', 'seld':'optr'($8010D50700600000$), 'from':null() }> could not be coerced to type {__CFURL=}.
PDF_document's writeToFile:temp_out_path
That’s right. It can bridge Cocoa objects (and a handful of types), but not Foundation pointers. You can’t create a context like that because (a) you can’t pass a Core Foundation type, and (b) even if you could, you couldn’t retrieve the result.
I’ve been playing around with this for a few hours, but I really can’t get it to work properly using PDFAnnotation. It’s not helped by the fact that there’s basically no sample code available from Apple.
I’m running into the same issue described here – it doesn’t appear possible to have the text box size itself to the supplied string, and Preview seems to be especially buggy when rendering it (PDF Expert seems fine?).
The text renders at the wrong size (appears to be about 24 pt, despite being set to 12 pt), and it’s cut off if the height value supplied for the annotation’s bounds is too small (though the exact relationship to font size is not clear). Double-clicking the annotation in Preview seems to irreversibly change some of its attributes but fixes the rendering issues.
Before double-clicking in preview (annotation height set to 10):
use scripting additions
use framework "Foundation"
use framework "PDFKit"
-- Get the input PDF.
set pdf_path to "/PATH/TO/PDF.pdf"
set file_URL to current application's NSURL's fileURLWithPath:pdf_path
set PDF_document to current application's PDFDocument's alloc()'s initWithURL:file_URL
set PDF_page to (PDF_document's pageAtIndex:0)
set {page_width, page_height} to item 2 of (PDF_page's boundsForBox:(current application's kPDFDisplayBoxMediaBox))
-- Set the output path.
set temp_out_path to "/PATH/TO/OUT.pdf"
set temp_out_URL to current application's NSURL's fileURLWithPath:temp_out_path
-- Create the annotation.
set annotation_position to {10, 10}
set annotation_height to 20
set PDF_annotation to current application's PDFAnnotation's alloc's initWithBounds:({{item 1 of annotation_position, page_height - (item 2 of annotation_position) - annotation_height}, {200, annotation_height}}) forType:(current application's PDFAnnotationSubtypeFreeText) withProperties:(missing value)
-- Set the annotation's properties.
PDF_annotation's setValue:"HELLO" forKey:"contents"
PDF_annotation's setValue:(current application's NSColor's clearColor()) forKey:"color"
PDF_annotation's setValue:0 forKey:"alignment" -- Left aligned.
PDF_annotation's setValue:(current application's NSFont's fontWithName:"Helvetica" |size|:12) forKey:"font"
-- Save the PDF.
PDF_page's addAnnotation:PDF_annotation
PDF_document's writeToFile:temp_out_path
Can anyone with some experience with PDFAnnotation point me in the right direction?
I’m starting to think that the problem lies with Preview not saving annotations in a standard format. I know they’ve always been a little buggy when opening the file with different PDF software (I’m on macOS 12.6.3, but the issue is hardly a new one).
use scripting additions
use framework "Foundation"
use framework "PDFKit"
use framework "AppKit"
-- define original and destination files
set theFile to current application's NSURL's fileURLWithPath:"/Users/zerafio/Desktop/test1.pdf"
set theDest to current application's NSURL's fileURLWithPath:"/Users/zerafio/Desktop/test2.pdf"
-- make new pdf copying the original
set theDoc to current application's PDFDocument's alloc()'s initWithURL:theFile
set thePage to (theDoc's pageAtIndex:0)
set {{pL, pB}, {pW, pH}} to (thePage's boundsForBox:(current application's kPDFDisplayBoxMediaBox))
-- create the annotation
set theAnnot to current application's PDFAnnotation's alloc's initWithBounds:{{pL + 20, pH - 40}, {pW - 40, 20}} forType:(current application's PDFAnnotationSubtypeWidget) withProperties:(missing value)
theAnnot's setWidgetFieldType:(current application's PDFAnnotationWidgetSubtypeText)
theAnnot's setFieldName:"textField"
theAnnot's setWidgetStringValue:"Mon paletot aussi devenait idéal"
theAnnot's setAlignment:0
theAnnot's setFont:(current application's NSFont's fontWithName:"Helvetica" |size|:12)
theAnnot's setBackgroundColor:(current application's NSColor's clearColor())
thePage's addAnnotation:theAnnot
-- make a new file
theDoc's writeToURL:theDest
-- open the new file in Preview
set theWorkspace to current application's NSWorkspace's sharedWorkspace()
set theConfig to current application's NSWorkspaceOpenConfiguration's new()
theConfig's setActivates:true
set appURL to (theWorkspace's URLForApplicationWithBundleIdentifier:"com.apple.Preview")
(theWorkspace's openURLs:{theDest} withApplicationAtURL:appURL configuration:theConfig completionHandler:(missing value))
@ionah Thank you, the script works very well
wondering if it cud be modified to replace existing text in a selected field/ annotation
or to get the bounds of a selected Annotation in a PDF
Cheers
Not easily. The code above operates directly on files, and is not controlling an application (so there’s no concept of “selected” in that case).
Unfortunately, Preview.app is not scriptable, so if that’s the application you’re using then you’re out of luck. If you’re using a different application, then that may be scriptable & you may be able to script it to pull the identifier of the selected annotation.