PDFium Component สำหรับ Delphi และ Lazarus แลกเปลี่ยนข้อมูลฟอร์มและคำอธิบายประกอบ (annotations) ผ่าน XFDF ซึ่งเป็นรูปแบบการแลกเปลี่ยน XML ที่กำหนดโดย ISO 19444-1 TPdf.ExportXFDF จะแปลงค่าฟิลด์ฟอร์มทุกฟิลด์และคำอธิบายประกอบที่รองรับทุกตัวในเอกสารที่โหลดให้เป็นอนุกรมลงในไฟล์ XFDF หรือ TStream; TPdf.ImportXFDF จะอ่านเอกสาร XFDF กลับเข้ามา สร้างคำอธิบายประกอบขึ้นใหม่บนหน้าของมัน และใช้ค่าฟิลด์ต่าง ๆ การเดินทางไปกลับเพียงครั้งเดียวดังกล่าวครอบคลุมสองเวิร์กโฟลว์ที่แอปพลิเคชันเอกสารทุกตัวต้องการในท้ายที่สุด: ผู้ตรวจสอบทำเครื่องหมายบน PDF ใน Acrobat แล้วส่งอีเมลความคิดเห็นถึงคุณเพื่อทำการผสานข้อมูล หรือกฎการปฏิบัติตามข้อกำหนดที่ระบุว่าข้อมูลฟอร์มต้องอยู่ในไฟล์แยกต่างหากที่สามารถตรวจสอบความแตกต่างและตรวจสอบได้ แทนที่จะฝังรวมอยู่ใน PDF เอง
PDFium รองรับการนำเข้าและส่งออก XFDF หรือไม่?
ตัวไลบรารี PDFium เองไม่รองรับ Native C API ไม่มีฟังก์ชัน XFDF หรือ FDF เลย — ไม่มีอะไรในส่วนหัวสาธารณะ (public headers) ที่อ่านหรือเขียนในสองรูปแบบดังกล่าว ดังนั้นการห่อโค้ด (wrapping) จำนวนเท่าใดก็ไม่ช่วยให้คุณไปถึงจุดนั้นได้ PDFium Component จึงใช้วิธีนำเอ็นจิน XFDF ทั้งหมดไปปรับใช้ใน Pascal ในยูนิตเฉพาะที่สร้างและแยกวิเคราะห์ XML โดยตรงบนโครงสร้างโมเดลข้อมูลคำอธิบายประกอบและฟิลด์ฟอร์ม TPdf ที่มีอยู่ ตัวเขียนจะสร้าง XML ด้วยมือและตัวอ่านคือตัวแยกวิเคราะห์เครื่องจักรสถานะ (state-machine parser) ที่เขียนด้วยมือ ดังนั้นฟีเจอร์นี้นี้จึงไม่มีการพึ่งพา Delphi XMLDoc หรือยูนิต FPC DOM และทำงานในลักษณะเดียวกันทั้งบน Delphi และ Lazarus
การตัดสินใจเลือกการออกแบบนี้มีความสำคัญเมื่อคุณประเมินทางเลือกอื่น ๆ หากคุณเคยเรียกใช้ฟังก์ชัน FPDF_* ดิบจาก Pascal ระบบ XFDF จะกลายเป็นกำแพง: ความสามารถดังกล่าวไม่อยู่ใน DLL คอมโพเนนต์นี้ก้าวข้ามกำแพงดังกล่าวโดยการปฏิบัติต่อ XFDF เป็นปัญหาการทำให้เป็นอนุกรมล้วน ๆ — รวบรวมค่าฟิลด์และบันทึกคำอธิบายประกอบที่ตัวห่อหุ้มรู้จักวิธีอ่านอยู่แล้ว เขียนออกมาเป็น XML มาตรฐาน และสลับกระบวนการเมื่อนำเข้า
ไฟล์ XFDF ประกอบด้วยอะไรบ้าง?
ISO 19444-1 กำหนด XFDF เป็นตัวแทน XML ของ FDF และเพย์โหลดของมันแบ่งออกเป็นสองบล็อกระดับบนสุด องค์ประกอบ <fields> จะเก็บชื่อฟิลด์ฟอร์มตามลำดับชั้นและค่าของมัน — ทุกอย่างที่ผู้ใช้พิมพ์ เลือก หรือทำเครื่องหมายใน AcroForm องค์ประกอบ <annots> จะเก็บคำอธิบายประกอบ: TPdf.ExportXFDF จะส่งประเภทคำอธิบายประกอบย่อย 18 ประเภทออกไป — text, highlight, underline, strikeout, squiggly, line, circle, square, caret, polygon, polyline, stamp, ink, freetext, fileattachment, sound, link และ redact คำอธิบายประกอบวิดเจ็ต (Widget annotations) ไม่มีอยู่ใน <annots> อย่างจงใจเนื่องจากข้อมูลของมันเดินทางใน <fields> และประเภทคำอธิบายประกอบย่อยภายในของโปรแกรมดูเอกสาร เช่น Popup จะไม่เป็นส่วนหนึ่งของคำศัพท์ XFDF
เพื่อให้การเดินทางไปกลับมีความถูกต้อง เรคคอร์ด TPdfAnnotation จึงได้รับการขยายเพิ่มด้วยข้อมูลเมตาที่ XFDF คาดหวัง: Name (ตัวระบุเฉพาะ NM), Subject, ModificationDate, CreationDate, Icon, Opacity, จุดสิ้นสุดเส้น, จุดยอดโพลีกอนและโพลีไลน์ และเส้นทางลายมือเขียนน้ำหมึก ฟิลด์ใหม่แต่ละฟิลด์จะจับคู่กับตัวเฝ้ายามบูลีน Has* ดังนั้นโค้ดที่สร้างคำอธิบายประกอบในเวอร์ชันก่อนหน้าจะยังคงคอมไพล์และสร้างพจนานุกรมเดียวกันต่อไป — ฟิลด์ที่ไม่ถูกกำหนดค่าจะไม่ถูกเขียนขึ้นมา หากคุณสร้างมาร์กอัปโดยใช้โปรแกรมอยู่แล้ว เรคคอร์ดเดียวกับที่คุณใช้สำหรับคำอธิบายประกอบมาร์กอัปข้อความที่มีพิกัดสี่เหลี่ยม (quad points) ตอนนี้จะเก็บทุกสิ่งที่ XFDF ต้องการ
คุณจะส่งออกข้อมูลฟอร์มและคำอธิบายประกอบไปยัง XFDF ได้อย่างไร?
การเรียกใช้งานเพียงครั้งเดียวจะส่งผลทั้งเอกสาร โหลด PDF โดยเปิดใช้งานการกรอกฟอร์ม เรียก ExportXFDF และคอมโพเนนต์จะไล่ดูทุกหน้า รวบรวมค่าฟิลด์และคำอธิบายประกอบ และเขียน XML ค่าส่งคืนคือจำนวนไบต์ UTF-8 ที่เขียน ซึ่งสามารถตรวจสอบความถูกต้องได้อย่างง่ายดายในบันทึกบันทึกย่อการทำงาน
var
Pdf: TPdf;
Bytes: Integer;
begin
Pdf := TPdf.Create(Self);
Pdf.FormFill := True; // needed so field values are live
Pdf.FileName := 'expense-report.pdf';
Pdf.Active := True;
Bytes := Pdf.ExportXFDF('expense-report.xfdf');
ShowMessage(Format('%d bytes of XFDF written', [Bytes]));
end;
ทั้งสองทิศทางมีโอเวอร์โหลด TStream ดังนั้นจึงไม่มีความจำเป็นต้องสร้างไฟล์ชั่วคราวบนดิสก์ การส่งออกไปยัง TMemoryStream เป็นรูปแบบธรรมชาติเมื่อ XFDF มุ่งหน้าไปยังการตอบกลับ HTTP, บล็อบฐานข้อมูล (database blob) หรือรายการในคลังเก็บถาวรที่มีลายเซ็นกำกับ
var
Buffer: TMemoryStream;
begin
Buffer := TMemoryStream.Create;
try
Pdf.ExportXFDF(Buffer); // same XML, no file involved
Buffer.Position := 0;
// hand the stream to a web response, blob column, or zip entry
finally
Buffer.Free;
end;
end;
ImportXFDF รวมความคิดเห็นกลับเข้าสู่เอกสารได้อย่างไร?
ฝั่งนำเข้าคือขั้นตอนสุดท้ายของเวิร์กโฟลว์ผู้ตรวจสอบ เพื่อนร่วมงานเพิ่มคำอธิบายประกอบในสัญญาภายใน Acrobat ส่งออกความคิดเห็นเป็นไฟล์ XFDF และส่ง XML ขนาดไม่กี่กิโลไบต์ให้คุณแทนที่จะส่งสำเนา PDF ฉบับที่สอง TPdf.ImportXFDF จะแยกวิเคราะห์ไฟล์นั้น สร้างคำอธิบายประกอบแต่ละตัวบนหน้าเว็บที่ระบุชื่อในแอตทริบิวต์ page ของมัน และเขียนค่าฟิลด์ลงในคำอธิบายประกอบวิดเจ็ตที่ตรงกัน ฟังก์ชันจะส่งคืนจำนวนฟิลด์รวมและคำอธิบายประกอบที่นำไปใช้ เพื่อให้ UI สามารถยืนยันปริมาณข้อมูลที่มาถึงได้อย่างถูกต้อง
var
Applied: Integer;
begin
Applied := Pdf.ImportXFDF('review-comments.xfdf');
StatusBar.SimpleText :=
Format('%d fields and annotations merged', [Applied]);
end;
ตัวแยกวิเคราะห์คือเครื่องสแกนแท็กที่เขียนด้วยมือซึ่งสร้างขึ้นเพื่อความยืดหยุ่นแทนที่จะเคร่งครัด: องค์ประกอบที่ไม่รู้จักจะถูกข้าม คำสั่งการประมวลผล การประกาศ DOCTYPE และความคิดเห็นจะถูกละเว้น ชื่อธงที่ไม่รู้จักจะถูกทิ้ง และค่าแอตทริบิวต์จะถูกถอดรหัสผ่านชุดเอนทิตี XML และการอ้างอิงอักขระตัวเลขทั้งหมด รวมถึงคู่ตัวแทน UTF-16 ไฟล์ XFDF ที่สร้างโดย Acrobat, โดยตัวแสดงผลบนเว็บ หรือโดยเครื่องมืออื่น ๆ จะรวมเข้ากันได้อย่างราบรื่น เมื่อคำอธิบายประกอบอยู่ในเอกสารแล้ว วงจรการตรวจสอบจะดำเนินต่อไปด้วยกลไกการตอบกลับและสถานะที่อธิบายไว้ในการสร้างเวิร์กโฟลว์การตรวจสอบคำอธิบายประกอบด้วย PDFium Component และค่าฟิลด์นำเข้าจะมีส่วนร่วมในตรรกะลำดับการสลับแท็บปกติที่ครอบคลุมในการนำทางฟิลด์ฟอร์ม
ทำไมตัวคั่นทศนิยมจึงมีความสำคัญต่อ XFDF?
คำอธิบายประกอบแต่ละตัวใน XFDF ถูกกำหนดตำแหน่งโดยสตริงพิกัด — rect="70.5,540,200,560" และอื่น ๆ — และ ISO 19444-1 กำหนดให้ใช้เครื่องหมายจุดทศนิยมเป็นตัวคั่น การจัดรูปแบบทศนิยมเริ่มต้นของ Delphi จะเป็นไปตามการตั้งค่าภูมิภาคของ Windows ดังนั้นในระบบภาษาเยอรมันหรือฝรั่งเศส ฟังก์ชัน FloatToStr แบบดิบจะเปลี่ยน 70.5 เป็น 70,5 ซึ่งทำให้รายการพิกัดที่คั่นด้วยลูกน้ำเสียหายกลายเป็นขยะที่ระบบประมวลผลอื่นปฏิเสธหรืออ่านผิด PDFium Component จะปรับตัวเลขทุกตัวที่เขียนให้เป็นมาตรฐาน: ตัวคั่นทศนิยมในเครื่องจะถูกเขียนใหม่ให้เป็นจุดทศนิยม และตัดศูนย์ที่อยู่ส่วนท้ายออก เพื่อให้ไฟล์ที่ส่งออกออกมาตรงกันทุกไบต์ ไม่ว่าจะสร้างบนเครื่องที่เป็น en-US หรือ de-DE หากคุณเคยดีบั๊กเครื่องมือ PDF ที่ทำงานได้ดีในสำนักงานแต่ล้มเหลวที่ไซต์ลูกค้าในยุโรป คุณเคยพบกับคลาสบั๊กชนิดนี้แล้ว — ยินดีที่จะแจ้งให้ทราบว่าคอมโพเนนต์นี้จัดการเรื่องนี้ให้คุณ
ข้อจำกัดของการเดินทางไปกลับคืออะไร?
ขอบเขตสองประการควรระบุให้ชัดเจน ประการแรก XFDF ขนส่งเฉพาะข้อมูลคำอธิบายประกอบ ไม่รวมรูปลักษณ์แสดงผลที่ถูกเรนเดอร์ — รูปลักษณ์ข้อมูล (appearance streams) ไม่ใช่ส่วนหนึ่งของรูปแบบไฟล์ ดังนั้นโปรแกรมดูที่เป็นผู้รับจะสร้างลักษณะคำอธิบายประกอบแต่ละตัวขึ้นใหม่จากคุณสมบัติของมัน ไฮไลต์หรือสี่เหลี่ยมจะเรนเดอร์ได้อย่างถูกต้องในทุกที่ ส่วนตราประทับที่มีรูปลักษณ์แบบกำหนดเองจะถอยกลับไปใช้สิ่งที่โปรแกรมดูเป้าหมายวาดขึ้นสำหรับชื่อตราประทับนั้น ประการที่สอง PDFium API พื้นฐานมีเมธอดกำหนดค่าสำหรับข้อความเท่านั้น แต่ไม่มีสำหรับจำนวนคำอธิบายประกอบหรือรูปทรงเรขาคณิตของเส้นทาง ดังนั้น Opacity, จุดสิ้นสุดเส้น, จุดยอด และเส้นทางลากหมึก จึงเป็นแบบส่งออกเท่านั้น: คอมโพเนนต์จะเก็บรักษาพวกมันไว้อย่างสมบูรณ์เมื่อเขียน XFDF แต่ไม่สามารถเขียนพวกมันกลับเข้าสู่ PDF ได้เมื่อนำเข้า ค่าฟิลด์ฟอร์ม, เนื้อหา, สี, สี่เหลี่ยมล้อมรอบ (rects), พิกัดสี่เหลี่ยม (quad points), วันที่ และข้อมูลเมตาเกี่ยวกับข้อมูลระบุตัวตน ล้วนเดินทางไปกลับได้ทั้งสองทิศทาง
สำหรับการเริ่มต้นใช้งานจริง ตัวอย่าง XfdfLab มาพร้อมกับชุดเดโม Delphi, C++Builder และ Lazarus และเชื่อมต่อการเรียกทั้งสองแบบเข้ากับปุ่มบน PDF ใด ๆ ที่คุณเปิด การรองรับ XFDF รวมอยู่ในการเปิดตัวปัจจุบันของ PDFium Component ควบคู่ไปกับ API คำอธิบายประกอบและแบบฟอร์มที่ใช้เป็นฐาน