การนำเข้า HTML5 Paged-Media
THPDFHTMLImporter.RenderHTML5 แปลงมาร์กอัป HTML5 และ CSS สำหรับพิมพ์ที่ทนทานเป็นคอนเทนต์ PDF ที่แบ่งหน้า พร้อมเก็บรักษาเส้นทาง RenderHTML แบบเดิมที่กระชับ
ความยาวแบบ CSS กับ Margin, BaseFontSize, ListIndent และ BlockSpacing ของ importer เป็นหน่วย point ทั้งหมด ไม่ว่าจะตั้ง THotPDF.Resolution ไว้เท่าไร renderer ทั้งสองตัวก็ได้หน้าเท่ากัน ส่วนการวาดของคุณเองก่อนและหลังการนำเข้ายังใช้ 1/Resolution นิ้วตามเดิม
การประกาศ
function RenderHTML5(
const HTML: WideString;
const AuthorStyleSheet: WideString = ''
): Boolean;
function HPDFRenderHTML5Document(
Doc: THotPDF;
const HTML: WideString;
const AuthorStyleSheet: WideString = '';
MarginPt: Single = 72;
const FontName: AnsiString = 'Arial';
FontSize: Single = 12
): Boolean;
สัญญาโปรไฟล์
HTML5ProfileVersion ส่งคืน 1 และ HTML5ProfileMilestones รายงานตัวแยกวิเคราะห์และ cascade เลย์เอาต์แบบแบ่งหน้า ตารางและฟอร์ม และทรัพยากรแบบจำกัด
- DOM ที่ทนทานยอมรับแท็กปิดท้ายที่ละไว้ทั่วไป เก็บลำดับข้อความ ข้ามบริเวณเอกสารที่ไม่แอ็กทีฟ และบังคับใช้
MaxDOMNodes - cascade รองรับ selector แบบ type, class, ID, equality attribute, descendant และ direct-child ลำดับต้นทาง น้ำหนักเฉพาะ การประกาศแบบ inline
!important,@media printและมาร์จิน@page - เลย์เอาต์แบบแบ่งหน้าสนับสนุนการไหลของบล็อก ส่วนหัว รายการ เส้นขอบ พื้นหลัง ระยะกล่อง การแบ่งหน้าอย่างชัดเจน ตาราง รูปภาพ และการแบ่งหน้าล้นอัตโนมัติ
- อินพุตข้อความ ปุ่ม ช่องทำเครื่องหมาย ปุ่มวิทยุ พื้นที่ข้อความ และตัวควบคุม select แสดงผลเป็นรูปลักษณ์แบบ static หรือฟิลด์ AcroForm เนทีฟเมื่อเปิดใช้
CreateAcroForms
ย่อหน้าที่วัดขนาดจริงและทิศทาง
ย่อหน้าตัดบรรทัดด้วย advance ที่วัดจากฟอนต์ปัจจุบัน ครอบคลุมการเปลี่ยนฟอนต์, run แบบ bold กับ italic, letter spacing, word spacing, การขึ้นบรรทัดใหม่แบบระบุเอง และขอบเขตอักขระเอเชียตะวันออก การจัดวางกับเครื่องหมายตกแต่งถูกใช้กับแต่ละบรรทัดที่ได้แยกจากกัน
direction: ltr, direction: rtl และ attribute dir ของ HTML เลือกทิศทางของย่อหน้า ส่วน dir="auto" ใช้ทิศทาง Unicode ของอักขระ strong ตัวแรก
บน Windows run สคริปต์สองทิศทางถูก resolve ด้วย Uniscribe และถูกจัดลำดับใหม่ข้ามขอบเขตสไตล์ โดยเอนจินข้อความ PDF เดิมจัดการ glyph shaping ภายในแต่ละ run ทิศทางของเอกสาร viewer preference และสถานะข้อความของหน้าที่บันทึกไว้จะถูกคืนหลังจบบรรทัด
การ override ทิศทางแบบ inline, bdi และ bdo ยังใช้ลำดับของย่อหน้าอยู่และให้ diagnostic เป็น hdkLayoutFallback ส่วน unicode-bidi อยู่นอกโปรไฟล์นี้ และการ shaping สคริปต์ยังเดินตาม shaping configuration ของเอกสาร
การแบ่งย่อหน้า
widows กับ orphans เป็นจำนวนเต็มบวกแบบสืบทอด ค่าเริ่มต้นทั้งคู่คือ 2 การแบ่งหน้าใช้ line box ที่วัดจริง ไม่ใช่จำนวนตัวอักษรที่ประมาณเอา
ตัวนำเข้าจะย้ายย่อหน้าหรือปรับจุดตัดเพื่อให้มีบรรทัดถึงจำนวนขั้นต่ำที่ขอทั้งก่อนและหลังจุดแบ่งหน้า ถ้าตั้ง break-inside: avoid ไว้ ย่อหน้าจะถูกรวมไว้เป็นก้อนเดียวเมื่อพอลงหน้าใหม่
เมื่อหน้าไม่พอสำหรับเงื่อนไขที่ขอ การ render จะคืบหน้าต่อโดยผ่อนเงื่อนไขลงและบันทึก diagnostic เป็น hdkPaginationConstraint แต่ละชิ้นของย่อหน้าจะได้พื้นหลังกับเส้นขอบของตัวเอง
การใส่ขีดกลางคำแบบเลือกได้
hyphens: none กดจุดตัดแบบ discretionary ส่วนค่าเริ่มต้น hyphens: manual ใช้ U+00AD หรือ ­ เครื่องหมายยัติภังค์ที่มองเห็นได้จะถูกปล่อยออกมาเฉพาะเมื่อจุดตัดนั้นถูกใช้จริง
hyphens: auto จะเรียก OnHyphenate เพิ่มด้วยคำกับค่า HTML lang ที่สืบทอดมา ถ้าไม่มี callback ก็ยังใช้จุดตัดแบบ manual และรายงาน layout fallback เพราะไม่มีพจนานุกรมภาษาแถมมาให้
ตำแหน่งตัดนับหน่วย UTF-16 code unit จากต้นคำ ตำแหน่งที่ผิด ออกนอกช่วง ตัดกลาง surrogate หรือตัดกลาง combining mark พื้นฐานจะถูกละเว้น
THPDFHTMLHyphenationEvent = procedure(
Sender: TObject;
const WordText, Language: WideString;
var BreakPositions: TArray<Integer>
) of object;
กล่อง flex กับ grid แบบมีขอบเขต
display: flex รองรับ row, row-reverse, column และ column-reverse ลูกของแถวใช้ความกว้างที่ระบุไว้หรือแบ่งความกว้างที่เหลือกัน และค่า flex-grow ที่เป็นบวกจะถ่วงน้ำหนักพื้นที่ส่วนเกิน
แถวรองรับ justify-content แบบ start, end, center, space-between, space-around และ space-evenly บวกการจัด cross-axis แบบ start, end, center และ stretch ส่วนการไหลแบบ column รองรับ layout แนวตั้งตามธรรมชาติ และให้ diagnostic เมื่อเจอการกระจายความสูงคงที่หรือการจัด cross-axis ที่ยังไม่รองรับ
display: grid รองรับ track คอลัมน์แบบความยาวคงที่ที่เป็นบวกและแบบ fr รวมถึง repeat(n, tracks) แบบมีขอบเขตที่มีได้สูงสุด 64 คอลัมน์ เซลล์ถูกวางตามลำดับในซอร์ส เติมทีละแถว
grid-column: span N กับ grid-column-end: span N ให้ลูกครอง track ต่อเนื่องกันพร้อมช่องว่างระหว่าง track ได้ ไอเท็มที่ไม่พอในแถวปัจจุบันจะไปแถวถัดไป และ span ที่ยาวกว่าจำนวน track จะให้ layout fallback
flex-wrap: wrap ขึ้นบรรทัดใหม่เมื่อความกว้างที่ระบุของไอเท็มถัดไปบวก gap ไม่พอ แต่ละบรรทัดใช้ flex-grow กับ justify-content ของตัวเอง ส่วน row-reverse กับ RTL กลับลำดับภายในบรรทัดนั้น ๆ โดยไม่ย้ายไอเท็มข้ามบรรทัด
gap รับความยาวหนึ่งหรือสองค่า พร้อม override row-gap กับ column-gap แยกจากกัน แถวที่อยู่ขนานกันต้องอยู่ในหน้าเดียวกันและถูกตรวจก่อนการวาด
ลูกแบบขนานรองรับ text block ที่มี inline styling, container block ธรรมดาที่ซ้อนกันได้แบบ recursive พร้อม padding, border และ background, container flex กับ grid ที่ซ้อนกัน, รูปภาพ และตัวควบคุมฟอร์มแบบ static หรือ native
รูปภาพใช้ byte จาก callback หรือ data URI คงอัตราส่วนเดิมไว้เมื่อไม่ได้ระบุความสูง และถูก decode หนึ่งครั้งต่อหนึ่ง DOM node ทั้ง preflight และ fallback ใช้ภาพแคชเดียวกันโดยไม่กินคำขอทรัพยากรเพิ่ม
กล่องลูกทั้งหมดถูกวัดก่อนวาดแถวขนานใด ๆ เนื้อหาที่ไม่รองรับหรือใหญ่เกินจึงไปเป็นการไหลแบบแนวตั้งธรรมดาโดยไม่ต้องวาดแถวเดิมซ้ำ การวางแผนที่ซ้อนถูกจำกัดที่ 64 ชั้นและกินงบประมาณ layout operation เดิม
ลูกที่ตัดบรรทัดโดยไม่ได้ระบุความกว้างจะครองหนึ่งบรรทัดเต็ม ส่วนตารางกับรายการภายในลูกแบบขนาน, flex basis กับ shrink, wrap-reverse, การวัดขนาด track จากเนื้อหา, track แถวกับ row span ของ grid และการวาง grid แบบชี้ตำแหน่งชัดเจน ยังอยู่นอกโปรไฟล์นี้และให้ diagnostic ที่สังเกตได้
Diagnostic ของ CSS ที่ไม่รองรับ
Diagnostics เปิดเผย record ที่มี Kind, Subject, Value และ MessageText ส่วน OnDiagnostic ได้รับข้อมูลชุดเดียวกันระหว่างการ render
property ที่ไม่รู้จัก, ค่าที่ไม่รองรับ, selector ที่ไม่รองรับ และ at-rule ที่ไม่รองรับ จะถูกละเว้นพร้อม diagnostic รวมถึงการประกาศในกฎ stylesheet ที่ไม่ถูกใช้เลย ส่วน selector แบบ pseudo ถูกข้ามแทนที่จะถูกนับเป็น type selector ธรรมดา
StrictCSS ซึ่งปิดอยู่ตามค่าเริ่มต้น จะ raise EHPDFHTMLUnsupportedCSS เมื่อมี diagnostic เนื้อหาก่อนหน้าอาจถูกปล่อยออกไปแล้ว ใครต้องการแบบ all-or-nothing จึงควรใช้เอกสารแยกต่างหาก
MaxDiagnostics ค่าเริ่มต้น 256 และจำกัดจำนวน record ที่เก็บไว้ หลังเกินลิมิตการเก็บ DiagnosticCount กับการส่งผ่าน callback ยังทำงานต่อให้สังเกตได้ และค่าที่ไม่เป็นบวกจะปิดการเก็บ record
ทรัพยากรแบบจำกัด
สไตล์ชีตภายนอก รูปภาพ และฟอนต์ @font-face ถูกปิดไว้เว้นแต่ OnResource จะให้ byte ของมัน การนำเข้า HTML จึงไม่เปิดไฟล์หรือเชื่อมต่อเครือข่ายเองเด็ดขาด
@font-face รองรับ source url(...) หนึ่งตัว, format('truetype') หรือ format('opentype') แบบเลือกได้, ชื่อ alias ของ family, style แบบ normal หรือ italic และ weight แบบ normal, bold, 400 หรือ 700 ส่วน font-display ยอมรับนโยบายมาตรฐาน เพราะการนำเข้าแบบออฟไลน์โหลดทรัพยากรเป็น synchronous
ฟอนต์ต้องเป็นทรัพยากร TrueType หรือ OpenType sfnt ที่ฝังได้ มีชื่อ family ของ Windows แบบ ASCII ยาวไม่เกิน 31 ตัวอักษร ส่วน WOFF, font collection, local(...), descriptor แบบ variable และ source list จะให้ diagnostic
ฟอนต์ที่ยอมรับจะถูกลงทะเบียนเป็นส่วนตัวในหน่วยความจำของ process บน Windows และถูกเอกสารเป็นเจ้าของจนกว่าเอกสารจะถูกทำลาย การปล่อย importer ก่อน EndDoc จึงไม่ทำให้การฝังฟอนต์แบบเลื่อนไปทำให้เสีย
ทรัพยากร data: กับผลลัพธ์ callback ใช้ขีดจำกัด MaxResources, MaxResourceBytes และ MaxTotalResourceBytes ร่วมกัน
MaxDecodedImageBytes ค่าเริ่มต้น 128 MiB และจำกัด cache ภาพที่ decode แล้วแยกต่างหากที่สี่ไบต์ต่อพิกเซล มิติของ BMP กับ PNG ถูกตรวจก่อนการ decode และทุกรูปที่ยอมรับถูกตรวจก่อนถูกเก็บไว้
MaxDOMNodes, MaxCSSRules และ MaxLayoutOperations จำกัดการแยกวิเคราะห์ การสร้าง cascade และงานเลย์เอาต์แยกจากกัน
THPDFHTMLResourceEvent = procedure(
Sender: TObject;
const URI: WideString;
ResourceKind: THPDFHTMLResourceKind;
var Data: TBytes;
var ContentType: string;
var Handled: Boolean
) of object;
สถิติ
THPDFHTMLImportStatistics รายงานเวอร์ชันโปรไฟล์ โหนดที่แยกวิเคราะห์ กฎ CSS งานเลย์เอาต์ การแบ่งหน้า ตาราง ตัวควบคุมฟอร์ม คำขอทรัพยากร การโหลดที่ยอมรับและปฏิเสธ ไบต์ทรัพยากรที่ยอมรับ บรรทัดข้อความที่วัดได้ บรรทัดที่มีการใส่ขีดกลางคำ diagnostic และจำนวน container flex กับ grid
OnLineLayout รับดัชนีหน้ากับบรรทัดย่อหน้าแบบฐานศูนย์ จุดเริ่มต้น ความกว้างกับความสูงที่วัดได้ ข้อความเชิงตรรกะ ทิศทาง และธงการใส่ขีดกลางคำ หลังจากข้อความ PDF จริงถูกปล่อยออกไปแล้ว
การเรียก RenderHTML5 ทุกครั้งรีเซ็ตระเบียนสถิติ และการละเมิดงบประมาณทำให้เกิด EHPDFHTMLImportBudget
ตัวอย่าง
Importer := THPDFHTMLImporter.Create(Doc);
try
Importer.CreateAcroForms := True;
Importer.MaxResources := 16;
Importer.RenderHTML5(
'<style>@page { margin: 36pt } ' +
'table { width: 100% }</style>' +
'<h1>Invoice</h1>' +
'<table><tr><td>Total</td><td>42</td></tr></table>' +
'<input name="approved" type="checkbox">'
);
finally
Importer.Free;
end;
ดูเพิ่มเติม: THPDFPage.TextOutHTML, Declarative Layout DOM, AcroForm Support