1

I'm trying to call the Acrobat Javascript API from VBA to flatten all annotations in a document, using the following code:

Sub flattenPDF()

Dim AcroApp As Acrobat.AcroApp
Dim AcroDoc As Acrobat.AcroPDDoc
Dim jso As Object
Dim path As String

path = "C:\Users\userID\Desktop\thisfile.pdf"

Set AcroApp = CreateObject("AcroExch.App")
Set AcroDoc = CreateObject("AcroExch.PDDoc")
AcroDoc.Open path
Set jso = AcroDoc.GetJSObject

jso.flattenPages
AcroDoc.Save PDSaveFull, path
AcroDoc.Close
AcroApp.Exit 

End Sub

The code runs successfully, but then when I open the PDF, all the annotations can still be edited--the flattening should have made them read-only, right?

Edit: I changed the first parameter of AcroDoc.Save from "1" to "PDSaveFull", and now the annotations are flattened if I run the script twice. Why don't they flatten the first time?

Update:

I modified the script to get the page count and pass it to flattenPages() per joelgaraci's suggestion, as well as passing in the PDF path to the function:

Sub flattenPDF(pdfPath As String)

Dim AcroApp As Acrobat.AcroApp
Dim AcroDoc As Acrobat.AcroPDDoc
Dim pageCount As Integer
Dim jso As Object

Set AcroApp = CreateObject("AcroExch.App")
Set AcroDoc = CreateObject("AcroExch.PDDoc")
AcroDoc.Open pdfPath
pageCount = AcroDoc.GetNumPages
Set jso = AcroDoc.GetJSObject
jso.flattenPages 0, pageCount - 1
AcroDoc.Save PDSaveFull, pdfPath
AcroDoc.Close
AcroApp.Exit

End Sub

But this got the same result: the annotations only flatten after I run the script twice.

sigil
  • 9,370
  • 40
  • 119
  • 199
  • 1
    Get the number of pages in the document then try jso.flattenPages(0, numPages-1) – joelgeraci Dec 29 '16 at 02:58
  • @joelgeraci, I tried this but the script still needs to be run twice to flatten the annotations (see my update in the OP). – sigil Dec 29 '16 at 17:58
  • It's possible that the delayed plugin loading is causing the flattenPages to fall on deaf ears the first time you run it. It's also possible that the annotations haven't been read either. Try adding jso.syncAnnotScan above the flatten line. That will force the annotations to be available to the JavaScript engine before you try to flatten. – joelgeraci Dec 29 '16 at 18:57
  • @joelgeraci, `jso.syncAnnotScan` didn't change anything. But I've also noticed that some PDFs do get flattened on the first run, so maybe it's something about how this particular PDF is constructed? – sigil Dec 29 '16 at 19:08
  • What are the results when you run this.flattenPages() from the Acrobat JavaScript console on the files that require two passes? – joelgeraci Dec 29 '16 at 21:37
  • I'm using Acrobat XI Standard, which doesn't have built-in functionality for accessing the JavaScript console. And due to companywide IT restrictions, I don't have administrator rights, which would be necessary for adding a script in the Adobe folder so that an Acrobat menu button can open the console with `console.show()`. Or is there another way to access the console? – sigil Dec 29 '16 at 21:45
  • Add a bookmark to the file that executes the JavaScript this.flattenPages(); – joelgeraci Dec 30 '16 at 02:53
  • @joelgeraci, that works successfully for an individual file, but it's not practical for processing a collection of files. – sigil Jan 04 '17 at 01:22
  • Agreed. I was just trying to determine if the problem was on the Acrobat JavaScript side or if it was in the VB interface to it. I still suspect that the problem lies in the delayed plugin loading. Is Acrobat already running when you run your app? – joelgeraci Jan 04 '17 at 19:31
  • @joelgeraci, no, the instance is created by the `CreateObject("AcroExch.App")` call. All the code snippets I've seen involving VBA automation of Acrobat create a new instance from scratch; how do I attach to a currently running instance of Acrobat? Maybe [iterating through process IDs](http://stackoverflow.com/q/26277214/619177), or something simpler? – sigil Jan 05 '17 at 19:34
  • Try starting Acrobat first. The object created is really just a hook to Acrobat, it's not running a separate instance. If your application is launch Acrobat "cold", there'll be a slight delay before the Forms plugin is loaded and the API to flatten is available. I think that's why it works the second time, it's run. If it works when Acrobat was already running, then you can add a bit of code to your application that will try to get the formsVersion property from the app object at a certain interval, say every 10 milliseconds, when it comes back not null, then it should be safe to flatten. – joelgeraci Jan 05 '17 at 21:58

1 Answers1

1

Just thought I would add my solution in case it helps someone... I wanted to flatten all PDF files in a folder and this seems to do the trick.

Sub Flatten_Folder()
Dim MyFile As String
Mypath = InputBox("Enter the path to the folder where the PDF files are 
Located **MUST END WITH \**")
MyFile = Dir(Mypath)
Do While MyFile <> ""
If MyFile Like "*.PDF" Or MyFile Like "*.pdf" Then
Fullpath = Mypath & MyFile
Set App = CreateObject("AcroExch.app")
Set avdoc = CreateObject("AcroExch.AVDoc")
Set pdDoc = CreateObject("AcroExch.PDDoc")
Set AForm = CreateObject("AFormAut.App")
pdDoc.Open (Fullpath)
Set avdoc = pdDoc.OpenAVDoc(Fullpath)
   js = "this.flattenPages();"
     '//execute the js code
    AForm.Fields.ExecuteThisJavaScript js

Set pdDoc = avdoc.GetPDDoc
pdDoc.Save PDSaveFull, Fullpath
pdDoc.Close
Set AForm = Nothing
Set avdoc = Nothing
Set App = Nothing
End If
MyFile = Dir
Loop
End Sub

On running the macro you get a message box prompt to paste the folder path in. Also this method seems to avoid the issue the OP was having.