Import HTML5 paginowanych mediów

THPDFHTMLImporter.RenderHTML5 konwertuje tolerancyjny znacznik HTML5 i CSS druku na paginowaną treść PDF, zachowując zwartą starszą ścieżkę RenderHTML

Długości CSS oraz Margin, BaseFontSize, ListIndent i BlockSpacing importera są w punktach, więc oba renderery produkują tę samą stronę niezależnie od ustawionego THotPDF.Resolution; własne rysowanie przed i po imporcie nadal używa 1/Resolution cala

Deklaracja

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;

Kontrakt profilu

HTML5ProfileVersion zwraca 1, a HTML5ProfileMilestones raportuje parser i kaskadę, układ paginowany, tabele i formularze oraz ograniczone zasoby

Mierzone akapity i kierunek

Akapity zawijają się z użyciem zmierzonych posunięć bieżącego fontu, łącznie ze zmianami fontu, przebiegami bold i italic, odstępami liter, odstępami słów, jawnymi łamaniami linii i granicami znaków wschodnioazjatyckich; wyrównanie i dekoracje stosują się osobno do każdej powstałej linii

direction: ltr, direction: rtl i atrybut HTML dir wybierają kierunek akapitu; dir="auto" używa kierunku Unicode pierwszego silnego znaku

Na Windows dwukierunkowe przebiegi skryptów są rozwiązywane przez Uniscribe i przestawiane przez granice stylów, podczas gdy istniejący silnik tekstu PDF zajmuje się shapingu glifów wewnątrz każdego przebiegu; kierunek dokumentu, preferencje przeglądarki i zapisany stan tekstu strony są przywracane po linii

Wbudowane nadpisania kierunku, bdi i bdo używają obecnie kolejności akapitu i dają diagnostykę hdkLayoutFallback; unicode-bidi wykracza poza ten profil, a shaping skryptów nadal podąża za konfiguracją shapingu dokumentu

Fragmentacja akapitów

widows i orphans to dziedziczone dodatnie liczby całkowite, oba domyślnie 2; paginacja używa zmierzonych line boxów, a nie szacowanej liczby znaków

Importer przenosi akapit albo koryguje jego podział tak, by przed i po przerwie strony zostawić żądaną minimalną liczbę linii; break-inside: avoid trzyma akapit w całości, gdy mieści się na świeżej stronie

Gdy strona nie może pomieścić żądanego ograniczenia, renderowanie robi postępy przez jego poluzowanie i zapisanie hdkPaginationConstraint; każdy fragment strony dostaje własne tło i obramowanie

Opcjonalne dzielenie wyrazów

hyphens: none wycisza łamania dyskrecjonalne, a domyślne hyphens: manual używa U+00AD lub ­; widoczny łącznik pojawia się tylko wtedy, gdy wybrane łamanie jest faktycznie użyte

hyphens: auto dodatkowo wywołuje OnHyphenate ze słowem i odziedziczoną wartością HTML lang; bez callbacku pozostają łamania ręczne i raportowany jest fallback układu, bo żadnego słownika językowego nie ma w pakiecie

Pozycje łamań liczą jednostki kodowe UTF-16 od początku słowa; pozycje nieprawidłowe, poza zakresem, dzielące pary zastępcze i dzielące podstawowe znaki diakrytyczne są ignorowane

THPDFHTMLHyphenationEvent = procedure(
  Sender: TObject;
  const WordText, Language: WideString;
  var BreakPositions: TArray<Integer>
) of object;

Ograniczone boxy flex i grid

display: flex obsługuje row, row-reverse, column i column-reverse; dzieci w wierszu używają jawnych szerokości albo dzielą pozostałą szerokość, a dodatnie wartości flex-grow ważują dodatkową przestrzeń

Wiersze obsługują justify-content start, end, center, space-between, space-around i space-evenly oraz wyrównanie osi poprzecznej start, end, center i stretch; przepływ kolumnowy obsługuje naturalny układ pionowy i emituje diagnostykę dla nieobsługiwanego rozkładu o stałej wysokości albo wyrównania osi poprzecznej

display: grid obsługuje dodatnie kolumny o stałej długości i fr, łącznie z ograniczonym repeat(n, tracks) do 64 kolumn; komórki są umieszczane w kolejności źródłowej, wypełniając wiersz po wierszu

grid-column: span N i grid-column-end: span N pozwalają dziecku zająć sąsiednie kolumny razem z interweniującymi odstępami; element, który nie mieści się w bieżącym wierszu, przechodzi do następnego, a rozpiętości większe niż liczba kolumn dają fallback układu

flex-wrap: wrap zaczyna nową linię, gdy jawna szerokość i odstęp następnego elementu nie mieszczą się; każda linia niezależnie stosuje flex-grow i justify-content, przy czym row-reverse i RTL odwracają pozycje wewnątrz każdej linii bez przenoszenia elementów między liniami

gap przyjmuje jedną lub dwie długości, z niezależnymi nadpisaniami row-gap i column-gap; równoległe wiersze pozostają na jednej stronie i są sprawdzane przed malowaniem

Dzieci równoległe obsługują bloki tekstu ze stylingiem inline, rekurencyjnie zagnieżdżone zwykłe kontenery blokowe z paddingiem, obramowaniami i tłami, zagnieżdżone kontenery flex i grid, obrazy oraz statyczne albo natywne kontrolki formularzy

Obrazy używają bajtów z callbacku albo data URI, zachowują własne proporcje, gdy nie podano wysokości, i są dekodowane raz na węzeł DOM; preflight i fallback ponownie używają tej samej zcache'owanej grafiki bez kolejnego żądania zasobu

Wszystkie boxy dzieci są mierzone przed zamalowaniem czegokolwiek w równoległym wierszu, więc zawartość nieobsługiwana albo zbyt duża schodzi do pionowego przepływu strony bez powtarzania zamalowanych wierszy; planowanie zagnieżdżania jest ograniczone do 64 poziomów i zużywa istniejący budżet operacji układu

Zawijające się dzieci bez jawnej szerokości zajmują jeden pełny wiersz; tabele i listy wewnątrz dzieci równoległych, flex basis i shrink, wrap-reverse, wewnętrzne wymiarowanie ścieżek, wiersze gridu i rozpiętości wierszy oraz jawne rozmieszczanie gridu pozostają poza tym profilem i dają obserwowalne diagnostyki

Diagnostyka nieobsługiwanego CSS

Diagnostics wystawia rekordy zawierające Kind, Subject, Value i MessageText; OnDiagnostic odbiera te same informacje podczas renderowania

Nieznane właściwości, nieobsługiwane wartości, nieobsługiwane selektory i nieobsługiwane at-rules są ignorowane z diagnostyką, łącznie z deklaracjami w nieużywanych regułach arkusza; selektory pseudo są pomijane, a nie traktowane jak zwykłe selektory typu

StrictCSS, domyślnie wyłączone, podnosi EHPDFHTMLUnsupportedCSS przy diagnostyce; wcześniejsza zawartość mogła już zostać wyemitowana, więc wywołujący wymagający importu wszystko-albo-nic powinni użyć osobnego dokumentu

MaxDiagnostics domyślnie 256 ogranicza przechowywane rekordy; DiagnosticCount i dostarczanie przez callback pozostają obserwowalne po osiągnięciu limitu magazynu, a niepozytywny limit wyłącza magazynowanie rekordów

Ograniczone zasoby

Zewnętrzne arkusze stylów, obrazy i fonty @font-face są wyłączone, chyba że OnResource dostarcza ich bajty, więc import HTML nigdy nie otwiera pliku ani połączenia sieciowego pośrednio

@font-face obsługuje jedno źródło url(...), opcjonalne format('truetype') lub format('opentype'), alias rodziny, styl normal lub italic oraz grubość normal, bold, 400 albo 700; font-display akceptuje standardowe polityki, bo import offline ładuje zasoby synchronicznie

Fonty muszą być osadzalnymi zasobami sfnt TrueType lub OpenType z ASCII nazwą rodziny Windows o długości co najwyżej 31 znaków; WOFF, kolekcje fontów, local(...), deskryptory zmiennych i listy źródeł dają diagnostyki

Przyjęte fonty są rejestrowane prywatnie w pamięci procesu na Windows i pozostają własnością dokumentu aż do jego zniszczenia, więc zwolnienie importera przed EndDoc nie unieważnia odroczonego osadzania fontów

Zasoby data: i wyniki wywołań zwrotnych współdzielą limity MaxResources, MaxResourceBytes i MaxTotalResourceBytes

MaxDecodedImageBytes domyślnie 128 MiB i niezależnie ogranicza zdekodowany cache obrazów do czterech bajtów na piksel; wymiary BMP i PNG są sprawdzane przed dekodowaniem, a każda przyjęta grafika przed jej zachowaniem

MaxDOMNodes, MaxCSSRules i MaxLayoutOperations niezależnie ograniczają parsowanie, konstrukcję kaskady i pracę układu

THPDFHTMLResourceEvent = procedure(
  Sender: TObject;
  const URI: WideString;
  ResourceKind: THPDFHTMLResourceKind;
  var Data: TBytes;
  var ContentType: string;
  var Handled: Boolean
) of object;

Statystyki

THPDFHTMLImportStatistics raportuje wersję profilu, parsowane węzły, reguły CSS, operacje układu, przerwy stron, tabele, kontrolki formularzy, żądania zasobów, zaakceptowane i odrzucone ładunki, zaakceptowane bajty zasobów, zmierzone linie tekstu, linie z podzielonymi wyrazami, diagnostyki oraz kontenery flex i grid

OnLineLayout odbiera zerowe indeksy strony i linii akapitu linii, początek, zmierzoną szerokość i wysokość, logiczny tekst, kierunek i flagę podziału wyrazów po faktycznym zapisaniu tekstu PDF

Każde wywołanie RenderHTML5 resetuje rekord statystyk, a naruszenia budżetu zgłaszają EHPDFHTMLImportBudget

Przykład

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;

Zobacz także: THPDFPage.TextOutHTML, Deklaratywne DOM układu, Obsługa AcroForm