기술 문서

Delphi에서 PDF 주석을 XFDF로 가져오기 및 내보내기

HotPDF는 현재 로드된 문서를 대상으로 작동하는 두 가지 함수인 ExportLoadedAnnotationsToXFDFImportLoadedAnnotationsFromXFDF를 통해 PDF 주석을 XFDF로 가져오고 내보냅니다. XFDF는 ISO 19444-1로 표준화된 XML 주석 교환 포맷이며, 이 한 쌍의 함수를 사용하면 Delphi 또는 C++Builder 프로그램에서 주석을 Acrobat 또는 타사 검토 도구로 전달하고 마크업된 결과를 다시 가져올 수 있습니다. 주석이 위치한 페이지 콘텐츠 자체를 다시 작성할 필요가 전혀 없습니다

이 기능이 해결하는 두 가지 방향을 떠올려 보십시오. 검토자가 Acrobat에서 생성된 보고서를 열고, 잘못 정렬된 다이어그램에 빨간색 화살표를 표시하고, 잘못된 합계에 동그라미를 치고, 여백에 메모를 작성한 뒤 이 주석들을 소형 XFDF 파일로 내보냅니다. 또는 반대로, 개발자의 프로그램이 주석을 직접 생성하고 HotPDF가 아닌 다른 도구를 사용하는 누군가에게 이를 전달해야 할 수도 있습니다. 두 경우 모두 주석은 양쪽 모두가 해석할 수 있는 XML로 전송되며, PDF 페이지는 바이트 단위 그대로 보존됩니다

FDF와 XFDF의 차이점은 무엇인가요?

FDF와 XFDF는 동일한 페이로드를 서로 다른 두 가지 구문으로 전송하므로, 다른 도구에 전달할 파일을 결정할 때 이 차이점을 고려해야 합니다. FDF는 PDF 사양 자체에 정의된 오래된 양식 데이터 포맷(Forms Data Format)입니다: 이는 PDF 개체 구문을 사용하므로 FDF 파일은 압축된 PDF 파일처럼 보이며 이를 읽으려면 PDF 인식 파서가 필요합니다. XFDF는 동일한 데이터를 XML로 표현하여 ISO 19444-1로 별도 표준화한 것이며, 이는 모든 플랫폼의 임의의 XML 라이브러리에서 이를 열거나, 비교(Diff)하거나, 생성할 수 있음을 의미합니다. 두 포맷 모두 ISO 19444-1 6.3항이 규정하는 <fields> 트리 내의 양식 필드 값과 <annots> 트리 내의 주석을 전송할 수 있습니다. HotPDF는 이러한 역할을 분할하여 양식 데이터는 ExportLoadedFormToXFDF를 통해 전송하고 ExportLoadedAnnotationsToXFDF<annots> 영역 전용으로 유보합니다. 웹 서비스, Java 검토 서버 또는 스크립트와 메모를 교환할 때, XFDF는 상대방에게 PDF 파서를 임베딩하도록 강제하지 않는 유용한 포맷입니다

How do you export PDF annotations as XFDF in Delphi?

HotPDF는 로드된 문서의 모든 페이지를 순회하며 지원되는 각 주석에 대해 하나의 XFDF 요소를 생성하고 작성된 주석 개수를 반환하여 주석을 내보냅니다. 먼저 PDF를 로드한 다음, 대상 경로와 함께 ExportLoadedAnnotationsToXFDF를 호출하십시오. 정수 반환 값은 직렬화된 주석의 수입니다: 반환 값이 0 이하이면 아무것도 내보내지 않고 파일도 생성되지 않았음을 의미하며, 이는 문서에 지원되는 하위 유형의 주석이 포함되어 있지 않다는 신호입니다

var
  Pdf: THotPDF;
  Written: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report-reviewed.pdf', '') > 0 then
    begin
      // 모든 페이지에서 지원되는 주석당 하나의 XFDF 요소를 작성합니다
      Written := Pdf.ExportLoadedAnnotationsToXFDF('comments.xfdf');
      if Written <= 0 then
        ShowMessage('No supported annotations were found');
    end;
  finally
    Pdf.Free;
  end;
end;

내보내는 XFDF는 평이하고 읽기 쉬운 XML입니다. HotPDF는 ISO 19444-1 네임스페이스의 <xfdf> 루트, <annots> 컨테이너, 그리고 0부터 시작하는 페이지 인덱스, 색상 및 기하학적 데이터를 속성이나 하위 요소로 보유하는 각 주석당 하나의 하위 요소를 작성합니다. 노란색 채우기와 빈 화살표 머리를 가진 선 주석이 칠해진 다각형 옆에 배치된 경우 다음과 같이 직렬화됩니다

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/">
  <annots>
    <line page="0" start="72,700" end="220,700"
          color="#FF0000" interior-color="#FFFF00"
          head="OpenArrow" tail="None">
      <contents-richtext>Baseline looks off</contents-richtext>
    </line>
    <polygon page="0" color="#0000FF" interior-color="#CCE5FF">
      <vertices>72,120;180,120;180,200;72,200</vertices>
    </polygon>
  </annots>
</xfdf>

주석 하위 유형(Subtype)이 XFDF 요소에 매핑되는 방법

각 주석 하위 유형은 고유한 지형 구조와 함께 특정 ISO 19444-1 요소에 매핑되며, HotPDF는 직접 임의의 구조를 만드는 대신 이러한 표준 구조를 따릅니다. 선(Line) 주석은 주석의 L 배열에서 직접 획득한 두 끝점 좌표 쌍을 포함하는 startend 속성을 가지며, LE 선 끝 스타일은 headtail 속성으로 변환됩니다. 다각형(Polygon) 및 다중선(Polyline) 주석은 점 목록을 속성이 아닌 하위 요소인 <vertices> 내부에 세미콜론으로 구분된 x,y 쌍으로 이동시킵니다: 하위 요소를 기대하는 리더는 다른 곳에 숨겨진 점 데이터를 감지하지 못하고 무시하기 때문입니다. 여러 개의 선 획을 가질 수 있는 잉크(Ink) 주석은 획당 하나의 <gesture> 하위 요소를 포함하는 <inklist> 요소를 중첩시키므로, 여러 개의 스트로크가 들어간 서명이 하나의 결합된 형태가 아니라 별개의 제스처들로 온전히 전달됩니다

서식 있는 텍스트(Rich text), 색상 및 테두리 스타일도 기하학적 형태와 함께 유지됩니다. 노트의 서식 있는 텍스트 본문은 <contents-richtext> 하위 요소로 작성됩니다; PDF가 IC 배열에 저장하는 내부 채우기(원, 사각형, 다각형 또는 선 화살표 내부의 페인트 및 리댁션 박스의 채우기)는 #RRGGBB 형태의 interior-color 속성으로 표시됩니다; 테두리 너비, 대시 패턴 및 구름 모양의 테두리 효과는 width, dashes, style, intensity 속성에 매핑되므로 구름 모양 테두리가 있는 콜아웃이 상대방 측에서도 구름 모양으로 올바르게 렌더링됩니다. 또한 HotPDF는 마크업 주석에 연결된 팝업 창을 유지하여 팝업 하위 구조와 열림/닫힘 상태를 주석의 Popup 딕셔너리로 가져오며, 텍스트 주석의 열림 및 검토 상태도 유지하므로 검토된 문서가 모양뿐만 아니라 검토자가 의존하는 워크플로우 메타데이터까지 함께 유지합니다

로드된 문서로 XFDF를 다시 가져오기

HotPDF는 XML을 파싱하고, NewLoadedAnnotation을 통해 각 요소에 대한 새 주석을 생성하여 해당 요소가 지정하는 페이지에 첨부한 뒤 추가된 주석 개수를 반환하여 XFDF를 가져옵니다. 이 워크플로우는 내보내기와 대칭을 이룹니다: 원본 PDF를 로드하고, 검토자의 파일과 함께 ImportLoadedAnnotationsFromXFDF를 호출한 뒤, 로드된 문서를 저장하여 새 마크업을 유지합니다. 파일이 누락되었거나 XML 파싱이 실패하면 함수는 0을 반환하고 로드된 문서는 변경되지 않은 채 그대로 유지됩니다

var
  Pdf: THotPDF;
  Added: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report.pdf', '') > 0 then
    begin
      Added := Pdf.ImportLoadedAnnotationsFromXFDF('comments.xfdf');
      if Added > 0 then
        Pdf.SaveLoadedDocument('report-annotated.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

각 XFDF 요소가 자체 페이지 인덱스를 지정하므로, 여러 파일을 차례로 가져오더라도 주석이 의도한 페이지에 정확하게 할당됩니다. 이는 한 번에 저장하기 전 여러 검토자의 피드백을 단일 문서로 취합할 때 매우 안전합니다. 아래 예시는 두 검토자의 주석을 하나의 최종 병합본으로 통합하는 루틴입니다. 파일 교환 대신 코드 상에서 주석 개체를 직접 생성하고 편집하는 방법에 대해서는 HotPDF에서 Delphi 코드로 직접 PDF 주석 개체 제어하기를 참조하십시오

var
  Pdf: THotPDF;
  Total, I: Integer;
  Files: array[0..1] of string;
begin
  Files[0] := 'alice-comments.xfdf';
  Files[1] := 'bob-comments.xfdf';
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('master.pdf', '') > 0 then
    begin
      Total := 0;
      for I := Low(Files) to High(Files) do
        Inc(Total, Pdf.ImportLoadedAnnotationsFromXFDF(Files[I]));
      if Total > 0 then
        Pdf.SaveLoadedDocument('master-merged.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

무엇이 온전히 왕복 전송되며 무엇이 그렇지 않나요?

HotPDF는 ISO 19444-1에 부합하는 주석 하위 유형을 온전히 왕복 전송하며, 리더가 잘못 해석할 수 있는 요소를 방지하기 위해 나머지는 의도적으로 건너뜜에 유의하십시오. 지원되는 주석 세트는 실제 검토 작업에서 주로 사용되는 마크업 유형을 포함합니다: 텍스트 메모, 자유 텍스트, 선, 사각형, 원, 다각형, 다중선, 네 가지 텍스트 마크업 유형(하이라이트, 밑줄, 취소선, 물결선), 스탬프, 잉크 및 캐럿(Caret), 그리고 파일 첨부, 사운드, 리댁션 및 링크 등 총 18가지 하위 유형입니다. 이 리스트에서 벗어나는 하위 유형의 주석은 내보낼 때 제외되며, 빈 상태로 기록되는 대신 완전히 제외되므로 함수가 반환하는 주석 카운트 값을 부풀리지 않습니다

서식 있는 텍스트는 유의해야 할 제한 사항입니다. HotPDF는 스타일이 적용된 텍스트와 일반 텍스트 본문이 온전히 전달되도록 <contents-richtext> 구조를 보존하지만, XFDF는 렌더링된 외관 스트림이 아닌 주석의 텍스트와 스타일 마크업만 전송합니다. 따라서 수신하는 프로그램은 HotPDF의 픽셀을 그대로 재현하는 대신 자체 글꼴과 레이아웃으로 팝업을 다시 그리게 됩니다. 왕복 전송은 픽셀 단위의 정확한 렌더링이 아닌 내용과 검토 의도를 충실하게 전달하는 수단으로 간주해야 합니다. 스타일이 적용된 콘텐츠가 주석 스트림이 아닌 XFA 양식 데이터에 위치하는 경우 동작 규칙이 다르며, HotPDF가 XFA exData, 서식 있는 텍스트 및 하이퍼링크를 처리하는 방법에서 해당 독립 경로를 다룹니다

문자 수준의 핸들링은 보기보다 엄격하며, 이는 신뢰성을 위해 꼭 필요한 부분입니다. HotPDF는 텍스트를 작성할 때 ISO 19444-1 5.8.2항의 이스케이프 규칙을 적용하여 XML에서 의미를 갖는 특수 문자 및 제어 바이트를 인코딩합니다: 이에 따라 앰퍼샌드(&), 꺾쇠 괄호(<>) 또는 줄바꿈이 포함된 메모가 표준 XML 파서가 해석할 수 있는 정상적인 형식으로 생성되고, 가져올 때 동일한 규칙이 역으로 적용됩니다. 스프레드시트 등에서 복사해 온 복잡한 문장 부호가 포함된 메모가 파일을 깨뜨리지 않고 올바르게 복원되는 이유가 바로 여기에 있습니다

주석 교환은 로드된 문서 API가 지원하는 기능의 일부분일 뿐이며, 다른 기능들과 조합하여 사용할 수 있습니다: 검토자의 XFDF를 가져오고, 페이지를 정렬하거나 문서 메타데이터를 편집하고, 문서를 플래트닝하거나 권한을 재조정한 뒤 다음 검토 단계를 위해 새로 XFDF를 내보낼 수 있습니다. 이 모든 기능은 주석 하위 유형과 양식 데이터 XFDF 함수 사양을 완벽하게 수록한 레퍼런스와 함께 Delphi 및 C++Builder용 표준 HotPDF 컴포넌트와 함께 제공됩니다