adobe SDK
adobe SDK

Reputation: 31

Integrate Adobe SDK in Delphi to edit PDF

I am working on an application where I need to be able to edit existing PDF form and drop PDF form fields interactively on the file.

Form fields like drop down, text, multi line text, radio button. Currently I am using ActiveX controls to open PDF files in an Delphi application.

However I can only read the PDF form but I want to be able to edit it also like drop an form field.

The idea is to add Form form on an existing PDF form and save it. I have tried Gnostice, PowerPDF, quickPDF but they do not allow interactively modify the PDF files like ADOBE. This online application PDFEscape allows us to create new and edit existing PDF forms interactively.

enter image description here

In Gnostic, we can Edit programmatically, like:

enter image description here

Questions:

Upvotes: 2

Views: 3159

Answers (1)

MartynA
MartynA

Reputation: 30715

The full version of Acrobat includes facilities to access & manipulate form fields from Delphi code, and supports operations such as adding form fields to a document, filling them in using code via OLE automation, and removing them if they are not needed.

You can certainly host an Acrobat window in your own app so that it displays f.i. in a TPanel. You can do this using the OpenInWindowEx method of the CAcroAVDoc object in Acrobat_TLB.Pas. However, this only draws the PDF document (plus annotations/comments, iirc), it doesn't provide display or provide access to Acrobat's gui. The only way I know to do that from from a Delphi app is to open the Pdf file in a TOleContainer object, but if you do that, Acrobat's gui opens in its own window, not hosted in one of yours. And the OleContainer interface looks positively antediluvian on-screen, these days.

So if you want interaction with Acrobat's form-fields editor gui, I think you're stuck. On the other hand, you can manipulate form fields and fill them in using your own DIY code - see the example below.

To do manipulate form fields in code, you need to import the Acrobat Forms type library into Delphi.
The type library you need to import is your equivalent to

D:\Program Files\Adobe\Acrobat 8.0\Acrobat\plug_ins\AcroForm.api 

You may need to register this file with Windows using Delphi's TRegSvr utility (or Windows' RegSvr32);

This gives you access to the IAFormApp object which is the top-level object for working with forms and, amongst others, the IField object, which is for creating an individual field.

If you have the Acrobat SDK documentation, the way to use to use these objects via Ole Automation is described in the "Interapplication Communication API Reference" (iac_api_reference.pdf). I've included the Delphi import of the IFIeld interface below so that you can see the sorts of things you can do with it.

"Is there a way where we can interactively edit a PDF form to drop Form fields?"

With the form open in Acrobat, yes you can drop a field (if by "drop" you mean "delete"). You can do this in code by calling the Remove method of the IFields interface. If, otoh, you mean "can we drop fields on the form" then yes, you can do that too, by creating a list of available fields and selecting a field from the list.

"Can we embedded Adobe or any other software in Delphi to edit an existing PDF?"

Yes, the following example shows how to fill in an existing field and add a new one, from Delphi code:

implementation

{$R *.DFM}

uses
  AFORMAUTLib_TLB, Acrobat_TLB;

const
  scDocument = 'D:\delphi\code\acrobat\blank.pdf';

procedure TForm1.FillInForm;
var
  Acrobat : CAcroApp;
  AVDoc : CAcroAVDoc;
  PDDoc : CAcroPDDoc;
  FormApp : IAFormApp;
  Fields : IFields;
  Field : IField;
begin
  Acrobat := CoAcroApp.Create;
  AVDoc := CoAcroAVDoc.Create;
  AVDoc.Open(scDocument, scDocument);
  PDDoc := AVDoc.GetPDDoc as CAcroPDDoc;

  FormApp := CoAFormApp.Create;

  Fields := FormApp.Fields as IFields;
  Field := Fields.Item['Text1'] as IField;
  Field.Value := 'My test';

  Field := Fields.Add('AnotherField', 'text',
  0,
  360,
  790,
  360 + 200,
  790 - 30) as IField;

  Field.Value := 'Added';
end;

Btw, I'm not sure whether you were intending to ask about this, but it's also possible to host Acrobat's gui in a window of a Delphi app. But if you want to know about that, you'll need to ask about it in a separate q, because it's a different technical issue.

Extract from AFORMAUTLib_TLB.Pas:

*********************************************************************//
    // Interface: IField
    // Flags:     (4416) Dual OleAutomation Dispatchable
    // GUID:      {673E8454-7646-11D1-B90B-00A0C9259304}
    // *********************************************************************//
      IField = interface(IDispatch)
        ['{673E8454-7646-11D1-B90B-00A0C9259304}']
        // getters amd setters omitted
        procedure SetBorderColor(const bstrColorSpace: WideString; GorRorC: Single; GorM: Single; 
                                 BorY: Single; K: Single); safecall;
        procedure SetBackgroundColor(const bstrColorSpace: WideString; GorRorC: Single; GorM: Single; 
                                     BorY: Single; K: Single); safecall;
        procedure SetJavaScriptAction(const bstrTrigger: WideString; const bstrTheScript: WideString); safecall;
        procedure SetSubmitFormAction(const bstrTrigger: WideString; const bstrTheURL: WideString; 
                                      theFlags: Integer; arrFields: OleVariant); safecall;
        procedure SetResetFormAction(const bstrTrigger: WideString; theFlags: Integer; 
                                     arrFields: OleVariant); safecall;
        procedure SetButtonIcon(const bstrFace: WideString; const bstrFullPath: WideString; 
                                pageNum: Smallint); safecall;
        procedure SetForegroundColor(const bstrColorSpace: WideString; GorRorC: Single; GorM: Single; 
                                     BorY: Single; K: Single); safecall;
        procedure PopulateListOrComboBox(arrItems: OleVariant; arrExportVal: OleVariant); safecall;
        procedure SetButtonCaption(const bstrFace: WideString; const bstrCaption: WideString); safecall;
        property Name: WideString read Get_Name;
        property Value: WideString read Get_Value write Set_Value;
        property IsHidden: WordBool read Get_IsHidden write Set_IsHidden;
        property IsTerminal: WordBool read Get_IsTerminal;
        property Type_: WideString read Get_Type_;
        property IsReadOnly: WordBool read Get_IsReadOnly write Set_IsReadOnly;
        property IsRequired: WordBool read Get_IsRequired write Set_IsRequired;
        property PrintFlag: WordBool read Get_PrintFlag write Set_PrintFlag;
        property BorderWidth: Smallint read Get_BorderWidth write Set_BorderWidth;
        property Alignment: WideString read Get_Alignment write Set_Alignment;
        property CharLimit: Smallint read Get_CharLimit write Set_CharLimit;
        property DefaultValue: WideString read Get_DefaultValue write Set_DefaultValue;
        property IsMultiline: WordBool read Get_IsMultiline write Set_IsMultiline;
        property IsPassword: WordBool read Get_IsPassword write Set_IsPassword;
        property CalcOrderIndex: Smallint read Get_CalcOrderIndex write Set_CalcOrderIndex;
        property BorderStyle: WideString read Get_BorderStyle write Set_BorderStyle;
        property Editable: WordBool read Get_Editable write Set_Editable;
        property Highlight: WideString read Get_Highlight write Set_Highlight;
        property Style: WideString read Get_Style write Set_Style;
        property TextFont: WideString read Get_TextFont write Set_TextFont;
        property TextSize: Smallint read Get_TextSize write Set_TextSize;
        property ButtonLayout: Smallint read Get_ButtonLayout write Set_ButtonLayout;
        property NoViewFlag: WordBool read Get_NoViewFlag write Set_NoViewFlag;
      end;

Update November 11 2021

I'm updating this answer in response to a deleted not-an-answer requesting exact details of how to generate the import units Acrobat_Tlb.Pas and AFORMAUTLib_TLB.Pas in a more recent version of Delphi.

The following method works with "Adobe Acrobat Standard 2020" purchased and installed from the Adobe online store and Delphi 10.4.2.

For Acrobat_Tlb.Pas

  1. Create a new VCL project and save the project and its form file.

  2. In the IDE, go to Component | Import Component and select Import a Type Library

  3. Click Next and on the Registered Type Libraries tab, enlarge the width of the Description column so you can view the full descriptions.

  4. Scroll down to the entry whose Description is just Acrobat. Click through the remaining tabs of the wizard, If you've got the right item, the ClassName(s) box on the next tab will contain "AcroApp=TAcroApp, AcroAVDocs=..."

    On the next tab, select the Create Unit radio button. Then click Finish and Acrobat_Tlb.Pas will be created.

For AFORMAUTLib_Tlb.Pas

Repeat the steps for Acrobat_Tlb.Pas with the following changes:

  1. In step 4, the Description you want is AFormAut 1.0 Type Library and the ClassName(s) box on the next tab should contain "AFormApp=TAFormApp,Fields= ..." and the generated import unit should be AFORMAUTLib_TLB.Pas

Upvotes: 8

Related Questions