losLab PDF Library는 세 가지 방법으로 PDF 양식 데이터를 내보내거나 가져옵니다. AcroForm 필드 값을 위한 FDF 및 XFDF, 주석 댓글을 위한 동일한 두 가지 포맷, 그리고 양식에 직접 쓰여지는 전체 XFA XDP 패킷입니다. ExportFormDataToXFDF, ImportFormDataFromXFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF 및 SetXFAFromString이 진입점이며, 각각 파일 버전과 문자열 버전을 모두 제공합니다
이처럼 다양한 메서드가 존재하는 이유는 PDF 양식 데이터가 단일한 형태가 아니기 때문입니다. 값을 채운 AcroForm에는 필드 값이 있고 검토 주석이 포함될 수도 있으며, 레거시 XFA 양식은 이 둘과 전혀 무관한 전체 XML 애플리케이션 설명을 포함합니다. losLab PDF Library는 이러한 세 가지 관심사를 별도의 API로 명확히 분리하여 관리합니다. 이를 통합하면 최소한 두 개의 데이터 모델에 맞지 않는 모델을 강제하게 되기 때문입니다. 어떤 제품군이 필요한지 결정하는 것이 설계의 첫 번째 선택이며, 이는 보통 수신 시스템이 실제로 소비하는 포맷이 무엇인지 파악하는 순간 결정됩니다
FDF, XFDF, XFA 양식 데이터의 차이점은 무엇인가요?
FDF와 XFDF는 두 가지 다른 구문으로 동일한 정보를 전달하며, XFA는 완전히 다른 세계입니다. FDF는 미니 PDF 구문 문서(ISO 32000-2 §12.7.8)로, PDF 내부에서 리터럴 문자열이 이스케이프되는 방식과 동일하게 이스케이프 처리된 문자열을 포함하는 << /T (이름) /V (값) >> 딕셔너리의 /Fields 배열입니다. XFDF는 동일한 데이터의 XML 형태(ISO 19444)로, Acrobat과 대부분의 양식 백엔드가 기본적으로 읽고 쓰는 <fields> 트리 구조입니다. XFA는 이 둘 다 아닙니다. 이는 PDF가 /AcroForm/XFA에서 참조하는 XML Data Package(XDP) 형태로 저장되는 XML Forms Architecture 템플릿과 해당 데이터입니다. 필드 값에 대해 상호 작용할 때는 FDF 또는 XFDF를 선택하고, 애초에 XFA 양식으로 작성된 문서를 유지 관리할 때만 XFA를 사용하십시오
losLab PDF Library는 FDF 및 XFDF 내에서 필드 값과 주석 댓글이라는 두 번째 구분선을 긋습니다. 양식 데이터 계열(ExportFormDataToFDF, ImportFormDataFromFDF, ExportFormDataToXFDF, ImportFormDataFromXFDF)은 /Fields 하위 트리만 읽고 쓰며 다른 것은 건드리지 않습니다. 반면 주석 계열(ExportAnnotationsToFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF, ImportAnnotationsFromXFDF)은 /Annots 하위 트리를 대신 다루며, 이는 Acrobat에서 '주석 내보내기'를 의미하는 것과 같습니다. 이 두 가지는 절대 겹치지 않으므로 필드 값을 내보낼 때 불필요한 검토 주석이 휩쓸려 들어가지 않고, 주석을 가져올 때 사용자가 이미 입력한 값을 손상시키지 않습니다. 위젯을 클릭하거나 다시 계산할 때 위젯이 수행하는 작업은 또 다른 독립된 관심사이며, 이는 대화형 양식 작업 및 JavaScript에 관한 기술 문서에서 다룹니다
Delphi에서 FDF 또는 XFDF를 통해 PDF 양식을 채우려면 어떻게 해야 하나요?
문서를 로드하고, 가져오기 메서드 중 하나를 호출한 뒤 저장하면 됩니다. ImportFormDataFromXFDF 및 ImportFormDataFromFDF는 들어오는 양식 데이터를 파싱하고 정식 이름(Fully qualified name)으로 AcroForm 필드와 매치한 뒤 값을 설정하고, 실제로 업데이트된 필드 개수를 반환합니다. 두 메서드 모두 대상 PDF에 이미 존재하는 필드만 업데이트하며, 양식에 정의되지 않은 필드를 무단으로 새로 생성하지 않으므로 외부의 잘못된 데이터 파일로 인해 양식의 크기가 임의로 늘어나는 것을 방지합니다
var
Lib: TPDFlib;
FieldsSet: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('application-blank.pdf', '');
// 케이스 관리 시스템에서 생성된 XFDF로, 이미 디스크에 UTF-8로 저장되어 있습니다
FieldsSet := Lib.ImportFormDataFromXFDF('applicant-1042.xfdf');
if FieldsSet > 0 then
Lib.SaveToFile('application-filled.pdf');
finally
Lib.Free;
end;
end;
유의미한 데이터가 정상적으로 전달되는지 여부는 두 가지 세부 사항에 의해 결정됩니다. 첫 번째는 이스케이프입니다. FDF는 값을 PDF 리터럴 문자열로 저장하므로, 괄호, 백슬래시 또는 출력할 수 없는 바이트가 포함된 값은 ISO 32000-2 §7.3.4.2에 정의된 8진수 이스케이프에 감싸여 수신됩니다. losLab PDF Library는 가져올 때 이 이스케이프 처리를 역으로 수행하므로 괄호와 슬래시가 사용자가 입력한 원래 문자로 복원됩니다. 두 번째는 인코딩입니다. 파일 기반 메서드는 UTF-8로 XFDF 및 FDF를 쓰고 읽는데, 이는 XFDF 선언이 보장하는 바이며 ASCII 이외의 필드 값(악센트가 있는 이름, 통화 기호, CJK 주소 등)이 깨짐 없이 온전히 왕복 전달되는 데 필요한 조건입니다. 직접 XFDF를 빌드하는 경우 UTF-8을 선언하고 UTF-8로 작성하면 가져오기 동작이 원활하게 수행됩니다
계층적 필드, 다중 선택 항목 및 서식 있는 텍스트
단순하게 구현된 내보내기 도구는 계층적 필드 이름에서 가장 먼저 오류를 냅니다. AcroForm은 중첩된 필드를 Applicant.FullName과 같이 점으로 구분된 전체 이름으로 지정하지만, XFDF는 단일 name 속성에 이 점으로 구분된 문자열을 직접 넣지 않습니다. ISO 19444에서는 이를 <field name="Applicant"><field name="FullName">와 같이 중첩 구조로 표현합니다. losLab PDF Library는 내보낼 때 점으로 구분된 타이틀을 중첩된 <field> 요소로 분할하고, 가져올 때는 이 중첩된 요소들을 다시 전체 이름으로 재구성하여 양방향 대칭성을 유지합니다. 또한 내보낼 때 최종 노드가 아닌 부모 필드는 건너뜁니다. AcroForm의 부모 노드는 명명 계층만 제공할 뿐 자체적인 값을 갖지 않기 때문에, 이를 출력하면 실제 양식과 맞지 않는 빈 <value></value>가 생성되기 때문입니다. 다중 선택 목록 상자는 두 번째 함정입니다. 선택 필드는 동시에 여러 개의 값을 가질 수 있으며, 이를 XFDF는 반복되는 <value> 요소로 표현하고 FDF는 /V 배열로 표현합니다. losLab PDF Library는 실제로 다중 선택인 경우에만 필드를 여러 값으로 분할하므로, 일반적인 다중 라인 텍스트 필드는 쪼개지지 않고 줄바꿈이 올바르게 유지됩니다
서식 있는 텍스트(Rich text)는 세 번째이자 가장 빈번하게 실수하는 영역입니다. 서식이 지정된 필드는 마크업을 XHTML 하위 트리 형식으로 RV 엔트리에 저장하고, XFDF는 이를 <value-richtext>에 담아 전달합니다. losLab PDF Library는 이 하위 트리를 이스케이프 처리하는 대신 실제 XML 프래그먼트로 기록하여, 다운스트림 도구가 화면에 표시되는 태그 문자열이 아닌 실제 서식 있는 텍스트를 읽을 수 있게 합니다. 가져올 때는 원시 RV 하위 트리를 유지하면서 일반 텍스트인 <value>를 V에 적용합니다. 필드가 두 가지를 모두 제공하는 경우, V에는 일반 텍스트가 우선 적용되고 RV에는 서식 있는 텍스트가 나란히 동반됩니다. 이는 서식 있는 텍스트를 가져올 때 다른 도구가 이미 설정한 값을 마음대로 덮어쓰지 않도록 하는 상호 운용성 규칙입니다. 보조 기술에 문서 구조를 전달하기 위해 서식 있는 텍스트를 사용하는 경우, 태그 지정된 PDF 및 접근성 구조에 관한 설명에 기술된 읽기 순서와 동일한 방식으로 처리하십시오
var
Lib: TPDFlib;
const
XFDF =
'<?xml version="1.0" encoding="UTF-8"?>' +
'<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">' +
'<fields>' +
' <field name="Applicant">' +
' <field name="FullName"><value>Alice Example</value></field>' +
' </field>' +
' <field name="Skills">' +
' <value>Delphi</value><value>PDF</value>' +
' </field>' +
' <field name="Notes">' +
' <value>See attachment</value>' +
' <value-richtext><body><p>See <b>attachment</b></p></body></value-richtext>' +
' </field>' +
'</fields></xfdf>';
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('intake.pdf', '');
// Applicant.FullName이 재구성됩니다. Skills는 /V + /I 배열을 채웁니다
// Notes는 <value>에서 V를 가져오고 <value-richtext>에서 RV를 가져옵니다
Lib.ImportFormDataFromXFDFString(XFDF);
Lib.SaveToFile('intake-filled.pdf');
finally
Lib.Free;
end;
end;
FDF 또는 XFDF를 사용하여 주석 댓글을 온전히 왕복 전달(Round-trip)하려면 어떻게 해야 하나요?
댓글은 주석 계열을 통해 이동하며, 지원되는 서브셋은 의도적으로 제한적입니다. ExportAnnotationsToXFDF 및 ImportAnnotationsFromXFDF(그리고 각각에 대응하는 FDF 메서드)는 깔끔하게 왕복할 수 있는 필드를 포함하는 텍스트 스타일 마크업만 다룹니다. 주석 하위 유형(Subtype), 사각형 영역(Rectangle), 0부터 시작하는 페이지 인덱스, T의 작성자, Subj의 주제, 일반 Contents, 그리고 PDF의 /C DeviceRGB 트리플을 XFDF의 #RRGGBB 속성과 상호 매핑하는 색상 정보 등입니다. 가져올 때는 알려진 요소 이름만 수락하고 페이지 범위를 벗어나거나 사각형 영역 정보가 누락된 항목은 건너뜁니다. 따라서 직접 편집했거나 출처를 알 수 없는 XFDF 파일이 문서 내에 비정상적인 주석을 삽입할 수 없습니다. 이 서브셋이 아직 다루지 않는 한계를 명확히 설명하자면, 서식 있는 텍스트 콘텐츠(RC), 팝업, 쿼드포인트(Quadpoints), 잉크 목록, 정점(Vertices) 및 구워진 외관 스트림(Appearance stream)은 현재 범위를 벗어나며, 하이라이트 지형 정보나 커스텀 스탬프의 외관은 이 경로를 통해 유지되지 않습니다. 실제로 무엇이 반영되었는지 확인하려면 페이지 주석이나 텍스트 검색 및 페이지 요소 열거에서 다루는 더 넓은 요소 트리를 순회하십시오
var
Src, Dest: TPDFlib;
Xfdf: WideString;
begin
Src := TPDFlib.Create;
Dest := TPDFlib.Create;
try
Src.LoadFromFile('reviewed.pdf', '');
Xfdf := Src.ExportAnnotationsToXFDFString; // <annots> 서브셋만 해당
Dest.LoadFromFile('clean-copy.pdf', ''); // 페이지 인덱스가 일치해야 합니다
Dest.ImportAnnotationsFromXFDFString(Xfdf);
Dest.SaveToFile('clean-copy-commented.pdf');
finally
Dest.Free;
Src.Free;
end;
end;
SetXFAFromString으로 전체 XFA XDP 패킷 작성하기
XFA는 다소 예외적인 아웃라이어이며, SetXFAFromString은 이 전체를 한 번에 쓰는 방법입니다. 이 메서드는 템플릿과 데이터셋 패킷을 포함하는 완전한 XML Data Package인 <xdp:xdp> 문서를 받아서 /AcroForm/XFA에서 참조하는 스트림에 저장합니다. losLab PDF Library는 문서에 AcroForm 컨테이너가 없을 때 이를 자동으로 생성하므로, XFA가 참조할 수 있도록 임의의 필드를 억지로 추가할 필요가 없습니다. 또한 기존에 보유하고 있던 파싱된 XFA 상태를 무효화하여 나중에 읽을 때 오래된 캐시 대신 방금 쓴 패킷이 올바르게 반영되도록 합니다. XFA 패킷은 XML 포맷이므로 항상 UTF-8로 구성되는 것은 아닙니다. 따라서 라이브러리는 UTF-16 바이트 순서 마크(BOM)를 감지하고 파싱 전에 적절히 디코딩하므로, 기본적으로 UTF-16을 출력하는 도구에서 생성된 패킷도 문제없이 처리합니다
패킷이 준비되면 GetXFAFormFieldValue 및 SetXFAFormFieldValue를 사용하여 스크립팅 개체 모델(SOM) 경로를 통해 개별 필드에 접근합니다. losLab PDF Library는 표준 SOM 루트뿐만 아니라 단순 상대 경로도 수락하므로 form1.FullName, $data.form1.FullName, xfa.datasets.data.form1.FullName이 모두 동일한 데이터 노드로 분석되며, 템플릿 영역의 $template과 xfa.template도 동일하게 작동합니다. 이러한 유연성은 항상 전체 정식 경로를 생성하는 다른 시스템에서 SOM 경로가 생성되는 경우에 매우 중요합니다
var
Lib: TPDFlib;
const
Xdp =
'<?xml version="1.0" encoding="UTF-8"?>' +
'<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">' +
' <template xmlns="http://www.xfa.org/schema/xfa-template/3.3/">' +
' <subform name="form1">' +
' <field name="FullName"><ui><textEdit/></ui></field>' +
' </subform>' +
' </subform>' +
' </template>' +
' <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">' +
' <xfa:data><form1><FullName>Alice Example</FullName></form1></xfa:data>' +
' </xfa:datasets>' +
'</xdp:xdp>';
begin
Lib := TPDFlib.Create;
try
Lib.SetXFAFromString(Xdp, 0); // 컨테이너가 존재하지 않는 경우 AcroForm 컨테이너를 생성합니다
// SOM 경로를 사용하여 데이터 DOM에서 값을 다시 읽습니다
if Lib.GetXFAFormFieldValue('form1.FullName') = 'Alice Example' then
Lib.SetXFAFormFieldValue('form1.FullName', 'Bob Example');
Lib.SaveToFile('xfa-packet.pdf');
finally
Lib.Free;
end;
end;
요약하자면, 필드 값은 계층 구조, 다중 선택 및 서식 있는 텍스트를 포함하여 FDF 및 XFDF를 통해 완전히 왕복(Round-trip)이 가능하고, 주석 댓글은 명확한 공백이 존재하는 제한된 텍스트 마크업 서브셋 형태로 왕복하며, XFA는 전체 패킷 단위로 쓰고 읽으며 상단에 필드별 SOM 접근을 지원합니다. 수신 시스템에 맞는 포맷을 사용하고, 수작업으로 빌드하는 모든 대상에 UTF-8을 선언하며, 가져오기 메서드는 문서 구조에 이미 부합하는 필드와 주석만 다룬다는 점을 기억하십시오. 여기에 설명된 양식 데이터, 주석 및 XFA 메서드는 Delphi 및 C++Builder용 losLab PDF Library의 일부이며, 해당 레퍼런스 문서에서 각 수출입 진입점에 대한 전체 매개변수 목록을 찾을 수 있습니다