如何使用Delphi将数据从XML导入PDF表单?

时间:2017-11-07 16:44:42

标签: xml delphi import delphi-10.2-tokyo pdf-form

我有一个PDF文件,里面装满了文本,数组,图像等等。还有文本字段。

我想知道是否以及如何导入格式正确的XML文件以填充这些文本字段,例如 Name,Surname,Address ...

我只想在Acrobat Reader菜单中执行类似此操作的操作:版本 - 表单选项 - 导入数据但使用Delphi编程。

我认为我需要打开PDF并使用函数来解析XML文件以填写表单但是现在我在网上找不到任何好的建议来解释如何做这样的事情

我希望我的问题是正确的,你可以回答我。

最好的问候。

1 个答案:

答案 0 :(得分:0)

下面是一些示例代码,它使用Acrobat的表单填充COM对象从使用Turbopower的XML Partner库解析的XML数据中填充Acrobat字段。由于某些外部依赖性,并且需要一些重构,它不可编译,但它应该给你一般的想法。 Calibrate例程添加了一些标记以帮助字段放置。

unit AcrobatXMLu;

interface

uses
  [...]
  Acrobat_tlb, //  main Acrobat COM wrapper
  AFORMAUTLib_TLB;  // Acrobat Forms COM objects

type
  TGenerateFlag = (gfShowAcrobat, gfUseDefaultValues, gfGenerateTestData, gfAddCalibration, gfAlwaysFillCheckboxes);
  TGenerateFlags = set of TGenerateFlag;

function CreateAcrobatFieldsInner(eStartNode: TxpElement;
  const Path: String; Flags : TGenerateFlags; const OutputFile : String): Boolean;

implementation

function CreateAcrobatFieldsInner(eStartNode: TxpElement;
  const Path: String; Flags : TGenerateFlags; const OutputFile : String): Boolean;
var
  List : TxpNodeList;
  X : TxpNode;
  N,
  Max : Integer;
  E : TxpElement;
  Align,
  S : String;
  AddedFields : TStringlist;

  procedure CreateField(E : TxpElement);
  var
    FieldName,
    FieldType,
    MappedFieldType : String;
    PageNo : Integer;
    ALeft,
    ARight,
    ATop,
    ABottom,
    AWidth,
    AHeight : Single;
    S : String;
    Field : IField;  //  Acrobat form field
    IsMultiLine : Boolean;
  begin
     FieldName := E.GetAttribute('Name');
     if CompareText(FieldName, 'Name1') = 0 then
       NoOp;
     FieldType := LowerCase(E.GetAttribute('PdfFieldType'));
     MappedFieldType := FieldType;
     if CompareText(MappedFieldType, 'checkbox') = 0 then
       MappedFieldType := 'text';
     IsMultiLine := CompareText(MappedFieldType, 'memo') = 0;
     if (CompareText(MappedFieldType, 'Text') = 0) or (CompareText(MappedFieldType, 'Memo') = 0) then
       MappedFieldType := 'text';

     Align := LowerCase(E.GetAttribute('Align'));
     S := E.GetAttribute('Page');
     if S = '' then
       S := TxpElement(E.ParentNode).GetAttribute('Page');
     if S <> '' then
       PageNo := StrToInt(S) - 1
     else
       PageNo := 0;
     S := GetHeritableAttribute(E, 'XPos', 'FieldXPos');
     ALeft := StrToInt(S);

     ATop := E.GetAttributeInt('YPos');

     S := GetHeritableAttribute(E, 'Width', 'FieldWidth');
     if S <> '' then
       AWidth := StrToInt(S)
     else
       AWidth := 60;
     S := GetHeritableAttribute(E, 'Height', 'FieldHeight');
     if S <> '' then
       AHeight := StrToInt(S)
     else
       AHeight := 20;
     ARight := ALeft + AWidth;
     ABottom := ATop - AHeight;

     try
       Field := Acrobat.Fields.Add(FieldName, MappedFieldType, PageNo, ALeft, ATop, ARight, ABottom) as IField;
       if True or (AddedFields.IndexOf(FieldName) < 0) then begin
         if CompareText(MappedFieldType, 'text') = 0 then begin
           S := GetHeritableAttribute(E, 'TextFont', 'FieldTextFont');
           if S <> '' then
             Field.Set_TextFont(S);
           S := GetHeritableAttribute(E, 'TextSize', 'FieldTextSize');
           if S <> '' then
             if not (CompareText(S, 'Auto') = 0) then
               Field.Set_TextSize(StrToInt(S));
           if IsMultiLine then
             Field.Set_IsMultiline(True);

           S := E.GetAttribute('DefaultValue');
           S := StringReplace(S, #10, #10#13, [rfReplaceAll]);
           if S <> '' then begin
             Field.Set_Value(S);
           end
           else begin
             if CompareText(FieldType, 'checkbox') = 0 then begin
               if gfAlwaysFillCheckboxes in Flags then
                 Field.Set_Value('X')
             end
             else begin
               if gfGenerateTestData in Flags then
                 Field.Set_Value(Format('(%s)', [FieldName]));
             end;
           end;
           if Align <> '' then
             Field.Set_Alignment(Align);
         end
         else begin
           if CompareText(MappedFieldType, 'checkbox') = 0 then begin
           end;
         end;
       end;
       if AddedFields.IndexOf(FieldName) < 0 then
         AddedFields.Add(FieldName)
     except
       ShowMessage('Error adding field ' + FieldName);
     end;
  end;

  procedure Calibrate;
  var
    X,
    Y,
    N,
    M,
    Page : Integer;
    Field : IField;  // Acrobat form field

    procedure AddField(X, Y : Integer);
    var
      S : String;
      FieldName : String;
    begin
      if X < 40  then
        S := Format('Y:%d', [Y])
      else
        S := Format('X:%d', [X]);
      FieldName := Format('X%dY%d', [X, Y]);
      Field := Acrobat.Fields.Add(FieldName, 'text', Page, X, Y, X + 40, Y - 15) as IField;
      Field.Set_TextFont('Courier');
      Field.Set_TextSize(10);
      Field.Set_Value(S);

    end;
  begin
    for Page := 0 to ((Acrobat.AcroApp.GetActiveDoc as CAcroAVDoc).GetPDDoc as CAcroPDDoc).GetNumPages - 1 do begin
      for N := 1 to 15 do
        AddField(40 * N, 0);
      N := 15;
      for M := 0 to 60 do
        AddField(0, N * M);
    end;
  end;

begin
  AddedFields := TStringlist.Create;
  AddedFields.Sorted := True;
  Result := False;
  try
    List := eStartNode.SelectNodes(Path);
    try
      Max := List.Length - 1;
      for N := 0 to Max do begin
        X := List.Item(N);
        if not (X is TxpElement) then Continue;
        E := TxpElement(X);
        S := E.GetAttribute('YPos');
        if S <> '' then
          CreateField(E);
      end;
      Result := True;
    finally
      List.Free;
    end;
    if gfAddCalibration in Flags then
      Calibrate;
    Acrobat.DocV.GetPDDoc.Save(PDSaveFull, OutputFile);
  finally
    AddedFields.Free;
  end;
end;

end.

如上所述,此代码添加了XML中定义的字段,并随着它们填充它们。显而易见;填补现有领域是一件小事。

Delphi的某些第三方PDF库也可以填写Acrobat字段。此外,命令行库PDFtk还可以填写Acrobat字段,并执行Acrobat COM对象无法执行的其他操作,例如&#34; flattening&#34; PDF表单,它有效地将字段中的文本合并到主文档中,因此不再可以作为表单进行编辑。有关详细信息,请参阅https://www.pdflabs.com/docs/pdftk-man-page/