Import annotations from one file to another using VBA exportAsFDF - vba

I am trying to import annotations from one file to another using VBA through adobe Javascript object interface.
So I want to export the fdf file of the pdf, so I am using exportAsFDF method.
However, it is exporting an FDF file without the annotations, only linking to the main file, which is different from the fdf file exported from Adobe GUI.
Here is my code below. I am already considering including annotations as True, which is the last parameter in exportAsFDF.
So does anyone know what's wrong with the code below?
Sub importComments()
Set AcroApp = CreateObject("AcroExch.App")
Set compositeDocument = CreateObject("AcroExch.PDDoc")
compositeDocument.Open ("C:\Users\...\sample.pdf")
Set sourceJSObject = sourceDocument.GetJSObject()
Set compositeJSObject = compositeDocument.GetJSObject()
Path = "C:\Users\C:\Users\...\trials.fdf"
Debug.Print compositeJSObject.exportAsFDF(True, True, "", True, Path, True)
End Sub

Related

Reading an .xltx file and Writing to .xlsx file with openpyxl

I've been struggling with this problem for a while and couldn't find a solution else where. I have several excel templates in xltx format that I want to read, then write a new xlsx file after filling in some cells.
Every time I run my code it creates a corrupted excel file. Using a preview extension in VS code I'm able to see that the values were correctly changed. When I read an xlsx file instead of an xltx it works fine. Does openpyxl just not allow what I am trying to do?
import openpyxl
import win32com.client
report = openpyxl.load_workbook("0100048-A5_R_11.xltx")
sheet = report["A5 form"]
search_arr = ["Test_Date"]
for r in range(2, sheet.max_row+1):
for c in range(3,sheet.max_column+1):
val = sheet.cell(r,c).value
if val != None and "$!" in str(val):
sheet.cell(r,c).value = 1
report.active = 1
report.save("output.xlsx")
Copied from the docs:
You can specify the attribute template=True, to save a workbook as a template:
wb = load_workbook('document.xlsx')
wb.template = True
wb.save('document_template.xltx')
or set this attribute to False (default), to save as a document:
wb = load_workbook('document_template.xltx')
wb.template = False
wb.save('document.xlsx', as_template=False)
Although the last line is from the latest docs, as_template is not a keyword argument for save!
This works instead:
wb.save('document.xlsx')

MS Word runs on background and requests documents to be saved even though it is already saved

I have a procedure that creates a PDF file according to an ms word template and its data is retrieved from a database.
It works fine, creates a PDF file perfectly , no run time errors. The problem is that whenever I shut off the computer, ms word prevents the shutdown and if I press cancel ms word shows a message;
The code goes like this;
Dim wordApp As Word.Application
Dim templateBookmarks As Word.Bookmarks
Dim templateName As String
Dim template As Word.Document
'Some other variables for computations
wordApp = CreateObject("Word.Application")
sourceTable = New DataTable
'Some other procs to fill the data table
templateName = "Foo Template.docx"
template = wordApp.Documents.Add(templatePath & templateName)
templateBookmarks = template.Bookmarks
templateBookmarks.Item("sample bookmark").Range.Text = "foo"
'Then fills the table in the template like...
template.Tables(1).Cell(1, 1).Range.Text = dataSource.Rows(0).Item(0)
'Then saves the document as a pdf
Dim saveName As String = "sample file"
template.SaveAs2(savePath & saveName, Word.WdSaveFormat.wdFormatPDF)
I have tried to force garbage collection for the word COM resources, as well as changing the template from an actual document i.e. docx to a word template .dotx. I also tried the method Quit() but it only shows the ms word message much earlier. This is the first time I needed to use interop so pardon if I don't have much idea about it.
The files I needed are saved, the only problem is the ms word message and unsaved and unnecessary files e.g. Document1,Document2,Document3 that seems to be created aside from the required PDF
Use the Document.Close method which closes the specified document after saving files using the PDF file format. It allows specifying the SaveChanges parameter which specifies the save action for the document. Can be one of the following WdSaveOptions constants: wdDoNotSaveChanges, wdPromptToSaveChanges, or wdSaveChanges.
On Error GoTo errorHandler
ActiveDocument.Close SaveChanges:=wdDoNotSaveChanges
errorHandler:
If Err = 4198 Then MsgBox "Document was not closed"

Fill a PDF Form from MS Access

I found a post on here on how to fill a fillable PDF from from MS Access.
It is a Visual Basic code for filling out a fillable PDF. I have been using Excel to perform this function and would like to migrate my database to Access and still keep the same functionality. I have figured out how to add my VB code to the button but when I click it gives me and error. Any help that can be giving would be greatly appreciated.
I have Adobe Acrobat X Pro and MS Access 2010. My PDF files was created in word and then converted to a PDF file, I know all my field names because I created them. The PDF document is saved as c:\CX.pdf, it has 9 pages, some examples of field names on the document are: “Plant Name”, “Station Location”, “Installer or Owner”. My MS Access Data Base Fields are named the same.
Option Compare Database
Private Sub Command105_Click()
Dim FileNm, gApp, avDoc, pdDoc, jso
FileNm = "c:\CX.pdf" 'File location
Set gApp = CreateObject("AcroExch.app")
Set avDoc = CreateObject("AcroExch.AVDoc")
If avDoc.Open(FileNm, "") Then
Set pdDoc = avDoc.GetPDDoc()
Set jso = pdDoc.GetJSObject
jso.getField("CX[0].Page1[0].Plant_Name[0]").Value = "Plant_Name"
jso.getField("CX[0].Page1[0].Station_Location[0]").Value = "Station_Location"
jso.getField("CX[0].Page1[0].Installer_or_Owner[0]").Value = "Installer_or_Owner"
pdDoc.Save PDSaveIncremental, FileNm 'Save changes to the PDF document
pdDoc.Close
End If
'Close the PDF; the True parameter prevents the Save As dialog from showing
avDoc.Close (True)
'Some cleaning
Set gApp = Nothing
Set avDoc = Nothing
Set pdDoc = Nothing
Set jso = Nothing
End Sub
It was giving me the error "Object not found", now it's not giving me error but it's still not writing to the PDF.
This is a bit old but it helped me in the long run. I did figure out what was wrong. "Object not found" means that the code cannot find the PDF field and therefore you can not assign anything to the object that "getFeild()" returns. The most likely culprit is that the "path" to the Field is incorrect. Try just putting the field name and you may need to export the data to a FTF file and read the file in notepad to find the field name.
the field names will look like
T/(FeildName)v/(FeildValue)
Once the object is actually being returned you'll be able to assign it a value.

Fill in a PDF form from VBA (MS-Access)

I want to fill a PDF form from my MS-Access 2003 .mdb project. The PDF has been created with Adobe LifeCycle Designer ES 8.2, all fields have significant names. However, the users who will run the PDf-filling functionnality don't have LifeCycle installed but only Adobe Reader 9.5 instead (might migrate to Adobe Reader X soon, I would like my code to be a little bit future proof).
How can I implement this? Most threads that I've seen on the Web redirect to the official Adobe SDK documentation, which is completely a mess when you're only doing VBA.
Thank you.
Finally managed to get something working after merging some lines of code. Here it is. It works with the Adobe Acrobat 9.0 Type Library set as reference in my VBA project.
Dim FileNm, gApp, avDoc, pdDoc, jso
FileNm = "c:\form.pdf" 'File location
Set gApp = CreateObject("AcroExch.app")
Set avDoc = CreateObject("AcroExch.AVDoc")
If avDoc.Open(FileNm, "") Then
Set pdDoc = avDoc.GetPDDoc()
Set jso = pdDoc.GetJSObject
jso.getField("topmostSubform[0].Page1[0].fieldName[0]").value = "myValue"
pdDoc.Save PDSaveIncremental, FileNm 'Save changes to the PDF document
pdDoc.Close
End If
'Close the PDF; the True parameter prevents the Save As dialog from showing
avDoc.Close (True)
'Some cleaning
Set gApp = Nothing
Set avDoc = Nothing
Set pdDoc = Nothing
Set jso = Nothing
Note that topmostSubform[0].Page1[0] is the default name that Adobe LiveCycle Designer gives to your main PDF document, while fieldName[0] is the name of your field. If you have multiple fields with the same name, Adobe LiveCycle Designer automatically adds index numbers so you can easily loop through your fields.

How to concatenate .pdf files with VBA?

I am trying to concatenate .pdf files with VBA. Nothing fancy, literally sticking the pages one after each other. I did numerous web searches but was unable to find any solutions that are even close to working. Has anyone done this before? Thanks!
If a GPL library is a valid option for you, you could use ghostscript as proposed in this SO question. You can do this by calling the ShellExecute function from Windows API or by using the class WScript.Shell if you are creating a vbscript file.
If a commercial library is an option, I recommend Amyuni PDF Creator ActiveX or Amyuni PDF Converter, both have an Append function that will do the work. The code for Amyuni PDF Converter for example would look like this:
Set PDFDoc = CreateObject("CDintfEx.Document.4.5")
PDFdoc.SetLicenseKey "your company", "your license code"
PDFDoc.Open "test_append1.pdf"
PDFDoc.Append "test_append2.pdf"
PDFDoc.Save "result_append.pdf"
Set PDFdoc = Nothing
Usual disclaimer applies for the latest suggestion
I found this topic while having the same task, with a customer using amyuni. Thanks to yms for a good approach. I found Acces crashing on "Set PDFdoc = Nothing". This one works fine for me:
Public Sub fctPDO_Concatenate_pdf_with_Amyuni_Document_6_0()
' PDO: Usage of .append: Crashes on destruction of pdfdoc-Object. pdf-file is created properly. But usind .append , MS Access crashes - without it's okay.
' Solution: Build second pdfdoc2 - object , and concatenate using .AppendEx(Object) .
On Error Resume Next
Dim PDFdoc As Object
Dim PDFdoc2 As Object
Const strLibraryVersion As String = "CDintfEx.Document.6.0"
' PDO: Examples
'Set PDFdoc = CreateObject("CDintfEx.Document.6.0") ' PDO: See Object catalog
'Set PDFdoc = CreateObject("CDintfEx.Document") ' PDO: Not sufficient w/o version
'Set PDFdoc = CreateObject("CDintfEx.Document.4.5") ' PDO: Older version
Set PDFdoc = CreateObject(strLibraryVersion)
Set PDFdoc2 = CreateObject(strLibraryVersion)
'PDO: Open first file
PDFdoc.Open "D:\PDO_test\Beratungsprotokoll_2018.pdf"
'PDFdoc.Append "D:\PDO_test\GV_0093Z0_Einzelantrag.pdf" ' PDO: Crashes on set PDFdoc = nothing
' PDO: Open and append second file (as Object, not as file)
PDFdoc2.Open "D:\PDO_test\GV_0093Z0_Einzelantrag.pdf"
PDFdoc.AppendEx PDFdoc2
' PDO: Open and append third file (as Object, not as file). Re-use of second Object possible
PDFdoc2.Open "D:\PDO_test\result_append_sammel.pdf"
PDFdoc.AppendEx PDFdoc2
'PDO: Save with a new name
PDFdoc.Save "D:\PDO_test\result_append_sammelsammel.pdf"
'PDFdoc.Close => Not existing.
Set PDFdoc = Nothing '=> Access crashed, with PDFdoc.Append
Set PDFdoc2 = Nothing
Debug.Print "Done: " & Now() & " Error: " & Err.Number
End Sub
If you prefer Ghostscript you can use a single line:
C:\PROGRA~2\gs\gs9.19\bin\gswin32c.exe -q -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOwnerPassword=pass2 -sUserPassword=pass1 -dCompatibilityLevel=2.0 -sOutputFile="D:\PDO_test\Beratungsprotokoll_2018_Sammel.pdf" "D:\PDO_test\Beratungsprotokoll_2018.pdf" "D:\PDO_test\GV_0093Z0_Einzelantrag.pdf"
This concatenates the two latter files into the (new) first one and applies a password (see security details before applying). The short path can be obtained with a FileScripting Object "fso" using
fso.GetFolder(strFolder).ShortPath
I run sedja-console and add my pdf's as parameters. Quite easy to implement. Do not forget to check before starting Sedja-console if the readonly flag of the possible previous created destination pdf isn't set to yes, as there is no feedback of this external process.