如何使用 Delphi 将数据从 XML 导入到 PDF 表单?
How to import data from XML to PDF Form using Delphi ?
我有一个 PDF 文件,其中包含文本、数组、图像等。还有文本字段。
我想知道是否以及如何导入格式正确的 XML 文件以填充这些文本字段,例如 姓名、姓氏、地址...
我只是想从 Acrobat Reader 的菜单中执行类似此操作的操作:版本- 表单选项 - 导入数据 但使用 Delphi编程.
我想我需要打开 PDF 并使用一个函数来解析 XML 文件以填写表格,但目前我没有在网上找到任何好的建议来解释如何做这样的事。
希望我的问题是正确的,希望你能回答我。
此致。
这里是一些示例代码,它使用 Acrobat 的表单填充 COM 对象来填充来自 XML 数据的 Acrobat 字段,这些数据是使用来自 Turbopower 的 XML 合作伙伴库解析的。由于某些外部依赖性,它不能按原样编译,并且需要进行一些重构,但它应该给你一个大概的想法。 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 的某些第 3 方 PDF 库也可以填写 Acrobat 字段。此外,命令行库 PDFtk 还可以填写 Acrobat 字段并执行 Acrobat COM 对象无法执行的其他操作,例如 "flattening" PDF 表单,它有效地将字段中的文本合并到宿主文档中,因此不再可编辑作为一种形式。有关详细信息,请参阅 https://www.pdflabs.com/docs/pdftk-man-page/。
我有一个 PDF 文件,其中包含文本、数组、图像等。还有文本字段。
我想知道是否以及如何导入格式正确的 XML 文件以填充这些文本字段,例如 姓名、姓氏、地址...
我只是想从 Acrobat Reader 的菜单中执行类似此操作的操作:版本- 表单选项 - 导入数据 但使用 Delphi编程.
我想我需要打开 PDF 并使用一个函数来解析 XML 文件以填写表格,但目前我没有在网上找到任何好的建议来解释如何做这样的事。
希望我的问题是正确的,希望你能回答我。
此致。
这里是一些示例代码,它使用 Acrobat 的表单填充 COM 对象来填充来自 XML 数据的 Acrobat 字段,这些数据是使用来自 Turbopower 的 XML 合作伙伴库解析的。由于某些外部依赖性,它不能按原样编译,并且需要进行一些重构,但它应该给你一个大概的想法。 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 的某些第 3 方 PDF 库也可以填写 Acrobat 字段。此外,命令行库 PDFtk 还可以填写 Acrobat 字段并执行 Acrobat COM 对象无法执行的其他操作,例如 "flattening" PDF 表单,它有效地将字段中的文本合并到宿主文档中,因此不再可编辑作为一种形式。有关详细信息,请参阅 https://www.pdflabs.com/docs/pdftk-man-page/。