代码之家  ›  专栏  ›  技术社区  ›  VirussInside

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

  •  0
  • VirussInside  · 技术社区  · 8 年前

    我有一个PDF文件,里面有文本、数组、图像等。。但也有文本字段。

    我想知道是否以及如何导入格式正确的XML文件以填充这些文本字段,例如 姓名、姓氏、地址。。。

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

    我假设我需要打开PDF并使用函数解析XML文件以填充表单,但目前我在网上没有找到任何好的建议来解释如何做这件事。

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

    顺致敬意,

    1 回复  |  直到 8 年前
        1
  •  0
  •   MartynA    8 年前

    下面是一些示例代码,它使用Acrobat的表单填充COM对象,从使用Turbopower的XML合作伙伴库解析的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对象无法执行的其他操作,例如“展平”PDF表单,这将有效地将字段中的文本合并到宿主文档中,因此不再作为表单进行编辑。看见 https://www.pdflabs.com/docs/pdftk-man-page/ 了解更多信息。