Die Bibliothek auf Ihrer eigenen Maschine

Die Engine, die die Dokumente schreibt, kommt in Ihre eigene Software, in Rust oder in Python, und erzeugt ihre Seiten auf Ihrer Maschine. Diese Seite sagt, was das für die Arbeit bedeutet, die Sie bereits haben.

Zusammenfassung

Worum es hier geht

Eine PDF-Datei sieht überall genau gleich aus. Sie öffnen sie auf Ihrem Computer, Ihr Nachbar auf einem Telefon, die Druckerei lässt sie über ihre Maschine laufen, und es ist auf den Millimeter dieselbe Seite. Deshalb reisen Rechnungen, Verträge und Gehaltsabrechnungen in dieser Form.

HQF Development stellt die Engine her, die diese Dateien schreibt. Kein Programm, das man öffnet und in dem man herumklickt: eine Engine, die die Person, die Ihre Software schreibt, in ihre eigene einbaut.

Was eine Bibliothek ist

In der Informatik ist eine Bibliothek eine Sammlung fertiger Teile. Denken Sie an einen Automotor. Ein Hersteller baut nicht für jedes Modell einen von Grund auf neu: Er nimmt einen vorhandenen Motor, setzt ihn in die Karosserie, die er entworfen hat, und verbindet das Pedal damit. Der Motor dreht die Räder; das Auto bleibt seines.

Eine Bibliothek ist diese Engine. Wer Ihre Rechnungssoftware schreibt, behält seine Software, seine Bildschirme, seine Gewohnheiten, seine Arbeitsweise. Er baut unsere Engine ein, sagt ihr: Hier sind die Rechnungspositionen, hier ist das Logo, hier ist die Summe, und die Engine gibt die PDF-Datei zurück.

Umgekehrt, und was sich ändert

Es gibt einen anderen Weg: die Informationen an einen Computer irgendwo im Internet senden, der das Dokument erzeugt und zurückschickt. Das ist, als brächte man seinen Brief zu einer Druckerei am anderen Ende der Stadt. Es funktioniert sehr gut, und das Team bietet auch das an. Aber man muss den Umschlag hinbringen, warten und ihn wieder abholen.

Mit der Bibliothek ist die Druckerei im Nebenzimmer. Drei Dinge ändern sich, und alle drei spürt man sofort.

  • Es geht sofort. Die Rechnung wird auf Ihrer eigenen Maschine erzeugt, im Moment des Klicks, der sie verlangt hat. Nichts geht hinaus, nichts kommt zurück.
  • Ihre Informationen bleiben bei Ihnen. Die Namen Ihrer Kunden, ihre Adressen, ihre Beträge bleiben von Anfang bis Ende auf Ihrer Maschine. Die Bibliothek arbeitet vollständig vor Ort, mit dem, was sie in ihrem eigenen Paket trägt. Ihre Daten verlassen nie die Maschine, die sie ausführt.
  • Sie steht für sich. Ihre Software erzeugt ihre Dokumente auch dann, wenn die Verbindung unterbrochen ist, und an einem abgeschotteten Standort. Die einzige Maschine, die man im Auge behalten muss, ist Ihre eigene.

Was es erzeugt

Rechnungen, Auftragsbestätigungen, Lieferscheine, Gehaltsabrechnungen, Verträge, Kontoauszüge, Etikettenbogen, Kataloge, Urkunden, Bordkarten, ganze Bücher. Mit Tabellen, die von einer Seite zur nächsten weiterlaufen, Logos, Fotos, den QR-Codes, die ein Telefon zum Bezahlen liest, Feldern, die Menschen am Bildschirm ausfüllen, und einem Passwort, das die Datei verschließt, wenn Sie danach fragen.

Was Sie erhalten, und wie es zu Ihnen gelangt

Die zu installierende Datei liegt auf der Download-Seite dieser Website, offen für alle: Sie klicken darauf, und sie wird auf Ihrem Computer gespeichert, genau wie jede andere heruntergeladene Datei. Ohne Lizenzschlüssel funktioniert sie bereits und versieht jede erzeugte Seite mit einem Wasserzeichen.

Ihr Lizenzschlüssel ist eine Folge von Buchstaben und Ziffern, nur Ihnen gehörend, die Ihre Software einmal erhält und die der Engine sagt, dass sie eine bezahlte Kopie ist: Das Wasserzeichen verschwindet. Sie legen ein Konto auf dieser Website an und zahlen, und Schlüssel und Rechnung warten in diesem Konto auf Sie. Geben Sie die Datei und diese Zeichenkette der Person, die Ihre Software entwickelt, und sie hat alles.

Ist eine neuere Datei bereit, liegt sie auf derselben Downloadseite, und Sie holen sie, wann es Ihnen passt.

Was Sie kaufen, ist das Recht, die Engine zu nutzen, gebaut und lauffertig. Ihr Quellcode bleibt bei HQF Development, so wie ein Autohersteller den Motor verkauft und die Pläne behält, nach denen er gebaut wurde.

Für wen diese Seite ist

Geben Sie die Adresse dieser Seite an die Person weiter, die Ihre Software entwickelt: Weiter unten findet sie alles, was sie braucht, um sie zu beurteilen.

Technisch

Eine Engine, auf zwei Wegen erreichbar — eine Rust-Bibliothek und ein Python-Wheel —, die öffentliche Schnittstelle, die sie bereitstellen, wie beide hier aus Ihrem Konto heruntergeladen werden und der Lizenzschlüssel, den sie zur Laufzeit lesen.

Zwei Bindings

Die Engine ist in Rust geschrieben und wird aus Rust direkt verwendet, als gewöhnliche Abhängigkeit Ihres Projekts.

Die Python-Seite ist eine kompilierte Erweiterung, bereits gebaut ausgeliefert: nichts auf dem Zielsystem zu kompilieren, keine Systembibliothek zu installieren, keine PDF-Werkzeugkette auf der Maschine. Sie ist gegen die stabile ABI von CPython gebaut: Ein Python-Wheel dient jeder Version des Interpreters ab CPython 3.9, unter Linux und Windows.

Eine C-API, um die Engine aus anderen Sprachen aufzurufen, ist für eine künftige Version geplant.

Was sie schreibt

  • Text: TrueType und OpenType geparst und eingebettet, auf die tatsächlich gezeichneten Glyphen gekürzt; Type 1 auf dieselbe Weise gekürzt; eine WOFF-Datei, die Form, in der ein Browser beliefert wird, als die Schrift in ihrer Hülle gelesen; Ligaturen, Kapitälchen, Mediävalziffern, Unterschneidung; eine Ersatzschrift hinter einer anderen; die vierzehn Standardschriften, die die Anzeigesoftware bereitstellen soll; Type-3-Schriften, deren Glyphen Zeichnungen sind; vertikales Schreiben.
  • Layout: auf eine Breite umbrochene Absätze, Spalten, Listen, Tabstopps und Füllpunkte, formatierte Abschnitte in einem Absatz, über so viele Seiten wie nötig umbrochene Tabellen, gestapelte Blöcke ohne eine einzige von Hand geschriebene Koordinate.
  • Zeichnen: Pfade, Kurven, Bögen, abgerundete Ecken, Beschneidung, axiale und radiale Verläufe, Kachelmuster, Transparenz und Füllmethoden, weiche Masken, wiederverwendbare Zeichnungen, so oft platziert wie gewünscht, zum Gewicht einer einzigen.
  • Bilder: JPEG, PNG und rohe Abtastwerte; Grau, RGB, CMYK, Palette; Alpha, Schablonenmasken, Beschneidungspfade, ICC-Profile, Ausrichtung.
  • Farbe: RGB, CMYK, Grau, kalibrierte Farbräume, L*a*b*, ICC-Profile, Sonderfarbe, mehrere benannte Farbmittel zugleich, indizierte Tabellen.
  • Codes: Code 128, Code 39, Code 93, ITF-14, Codabar, EAN-13, UPC-A, EAN-8, UPC-E, GS1 DataBar, die zwei- und fünfstelligen Add-ons, QR-Code, Data Matrix, PDF417, Aztec.
  • Interaktive Teile: Textfelder, Kontrollkästchen, Dropdown-Listen, Optionsgruppen, Schaltflächen, Signaturfelder, Links, Lesezeichen, Seitenbeschriftungen, Artikelflüsse, Ebenen, Seitenübergänge.
  • Normen: PDF/A für die Archivierung, PDF/X für den Druck, PDF/UA für die Barrierefreiheit, Factur-X für die elektronische Rechnung, XMP-Metadaten mit eigenen Schemata, vollständiges Seiten-Tagging.
  • Schutz: AES-256-Verschlüsselung, Benutzer- und Eigentümerpasswort, Berechtigungen pro Aktion.
  • Lesen: ein von einem anderen Programm geschriebenes PDF öffnen und seine Seiten, Metadaten, Links, Formularfelder, Lesezeichen, Ebenen und Struktur lesen; eine ganze Seite daraus in das Dokument übernehmen, das Sie schreiben.
  • Dateigewicht und Zeit bis zur ersten Seite: Kompressionseinstellung, Objektstreams, linearisierte Ausgabe.

Was geliefert wird, und wie ein Build darankommt

Die Lieferung ist ein Download von dieser Website. Die Download-Seite ist für alle offen, und jede Datei darauf trägt ihre Version: das Python-Wheel für die Python-Seite und die kompilierte Rust-Bibliothek für die Rust-Seite. Ein Klick lädt die Datei herunter. Eine Kopie ohne Lizenzschlüssel läuft und versieht jede erzeugte Seite mit einem Wasserzeichen; der Schlüssel, und nichts anderes, hebt es auf. Wenn Sie per Karte bezahlt haben, wird der Link zur Download-Seite auch an die angegebene Adresse gesendet.

Das Python-Wheel wird unverändert in eine virtuelle Umgebung installiert. Die Rust-Seite wird in Ihrem Manifest gegen die heruntergeladene Kopie deklariert, sodass ein Build sie aus Ihrem eigenen Speicher auflöst, wie er jede andere festgelegte Abhängigkeit auflöst — und sie innerhalb eines Netzes auflöst, das nichts außerhalb seiner selbst erreicht.

Ihr Lizenzschlüssel liegt auf derselben Kontoseite wie die Artefakte und die Rechnungen. Er ist eine signierte Zeichenkette, zur Laufzeit aus einer Datei, einer Umgebungsvariablen oder einem Secrets-Manager gelesen und dem Dokument in einem Aufruf übergeben. Was die Lizenz kauft, ist das Recht, die kompilierte Engine auszuführen, wie es die Verkaufsbedingungen darlegen; der Quellcode bleibt bei HQF Development.

Eine neuere Version wird auf derselben Seite veröffentlicht; ein Upgrade heißt also, das gewünschte Artefakt herunterzuladen und Ihre feste Versionsangabe darauf zu setzen. Der Lizenzschlüssel, den Sie bereits haben, funktioniert weiter.

Was es von der Maschine verlangt, die es ausführt

Sie funktioniert sofort. Alles, was sie braucht, steckt im Paket: die Metriken der vierzehn Standardschriften, das eine Farbprofil, das sie selbst baut, die Codetabellen. Eine Prüfung liest die ausgelieferte Datei selbst und listet jeden Aufruf nach außen auf, den sie machen kann: Sie schlägt fehl, wenn auch nur einer davon eine Verbindung öffnen, einen Namen im Netz nachschlagen oder eine verschlüsselte Sitzung starten könnte. Ihre Daten bleiben auf der Maschine, auf der sie läuft.

Ein signierter Lizenzschlüssel, den das Team beim Kauf aushändigt, schaltet sie frei. Der Schlüssel wird aus einer Datei, einer Umgebungsvariablen oder einem Secrets-Manager gelesen und dem Dokument in einem Aufruf übergeben. Bevor ein Schlüssel übergeben ist, schreibt die Engine eine Evaluierungskopie: Jede Seite kommt mit einem Wasserzeichen heraus, jeder Buchstabe wird als Form nachgezeichnet statt als Text geschrieben, die Datei enthält keine Schrift, es werden kein Formular und keine Struktur geschrieben, und eine Handvoll Aufrufe lehnt rundweg ab, unter Nennung der Lizenz, die sie erfordern. Es ist eine funktionierende Erprobung der Form eines Dokuments.

Wie ein Dokument zusammengesetzt wird

Immer dieselbe Form: ein Dokument erzeugen, ihm Ressourcen hinzufügen — eine Schrift, ein Bild, eine Zeichnung, einen Verlauf —, von denen jede ein Handle zurückgibt, einen Inhaltsstream mit Zeichenoperatoren füllen, daraus eine Seite erzeugen, die Seite dem Dokument hinzufügen, die Bytes anfordern.

Drei Layout-Engines sitzen über diesem Unterbau und ersparen Ihnen jede Koordinate: Der Textfluss bricht einen Absatz auf eine Breite um, die Tabelle misst ihre Zeilen an ihrem Inhalt und teilt sich selbst auf Seiten auf, der Stapel setzt Blöcke untereinander. Daneben: Farbe, Bilder, Formulare, Navigation, Metadaten, Konformität, Schutz und das Lesen eines bestehenden PDF.

Das Detail, mit seinen Zahlen

Die Zahlen Familie für Familie, dasselbe Programm auf beiden Seiten geschrieben und die Form, in der eine Ablehnung zurückkommt.

Die öffentliche Schnittstelle auf einen Blick

Version 1.364.0 der Engine stellt 49 öffentliche Module und 262 Namen auf der Wurzelebene des Rust-Crates bereit; die Python-Seite deklariert 434 Klassen, weil dort ein Namensraum enthält, was Rust in einem Modul pro Familie hält. 135 vollständige Beispiele werden mitgeliefert, jedes in zwei Zwillingsfassungen, eine in Rust und eine in Python. Bevor eine Änderung in die Bibliothek gelangt, wird jedes davon in beiden Sprachen ausgeführt und die beiden Dateien Byte für Byte verglichen, damit keines unbemerkt veraltet.

Familie Was darin ist
Dokument und Seite Document, Page, Content, Version, Compression, PageGroup, PageTurn, TabOrder
Schriften und Text Font, FontHandle, StandardFont, Type1Font, Type3Font, MissingGlyph, Run, WritingMode
Layout TextFlow, Table, Row, Cell, Columns, ColumnWidth, RichText, Style, Rect, Shadow
Gestapelte Blöcke, Tabellenlinien und Stempel layout: Stack, Block, FittedTable, Rule, Stroke, Border, Padding, Margin, VerticalFlow, TaggedTable, Stamp
Farbe Color, Rgb, Cmyk, Paint, CalGray, CalRgb, Lab, IccBased, Indexed, Separation, DeviceN, OutputIntent
Bilder und Einpassen Image, ImageHandle, ImageSpace, Resolution, Orientation, ClippingPath, FitBox, FitMode, Anchor, Turn, Mirror
Verläufe, Muster, Funktionen Axial, Radial, TilingPattern, Spacing, Function, Calculation, Op
Grafikzustand ExtGState, BlendMode, SoftMask, OverprintMode, BlackPointCompensation
Zeichnungen und Ebenen Drawing, Layer, LayerConfiguration, LayerRule, LayerPolicy, LayerIntent, LayerPurpose, LayerWork, PageRole
Codes Code128, Ean13, Ean8, UpcA, QrCode, DataMatrix, Pdf417, Aztec
Formulare und Signieren TextField, CheckBox, ChoiceField, RadioGroup, PushButton, SignatureField, FieldBorder, Signature, Signer, IncrementalUpdate
Navigation Bookmark, Link, Article, PageLabel, OpenAction, PageFit, ViewerPreferences, Transition und alles, was das Aktionsmodul enthält
Annotationen das Annotationsmodul: Quadrate, Kreise, Linien, Polygone und Linienzüge
Barrierefreiheit StructureTree, StructElement, Marks, Scope, Artifact
Metadaten und Normen metadata: Metadata, Xmp, XmpSchema, PdfA, PdfX, PdfUa, Invoice, Attachment; Standard, Report, Finding
Schutz Encryption, Permissions
Lesen read: Reader, ImportedPage, Information, FormEntry, Outline, LayerEntry, Structure, Parts
Lizenz und Meldung License, Error, Warning, ResourceKind
Niedrige Stufe cos, filter, incremental, platform

Das kürzeste nützliche Dokument

In Rust

use hqf_pdf::content::Content;
use hqf_pdf::cos::Name;
use hqf_pdf::{Document, License, Page};

let mut c = Content::new();
c.set_fill_rgb(0.20, 0.40, 0.80)?;
c.rect(50.0, 700.0, 495.0, 90.0)?;
c.fill();

let mut page = Page::a4();
page.content = c.into_bytes();

let mut doc = Document::new();
doc.set_license(License::from_key(key)?);
doc.set_info(Name::new("Title"), "hqf-pdf sample invoice");
doc.add_page(page)?;

let bytes = doc.to_bytes()?;

In Python

import hqf_pdf

content = hqf_pdf.Content()
content.set_fill(hqf_pdf.Rgb(0.20, 0.40, 0.80))
content.rect(50.0, 700.0, 495.0, 90.0)
content.fill()

page = hqf_pdf.Page.a4()
page.set_content(content)

document = hqf_pdf.Document()
document.set_license(hqf_pdf.License.from_key(key))
document.set_info("Title", "hqf-pdf sample invoice")
document.add_page(page)

data = document.to_bytes()

Text in einer eingebetteten Schrift

Nur die Glyphen, die das Dokument zeichnet, kommen in die Datei: Eine Seite mit einer Zeile trägt Schrift für eine Zeile, nicht die ganze Schrift. Gemessen wird über dasselbe Handle, das zeichnet; so bleibt Text in seinem Kasten.

In Rust

let font = Font::parse(fs::read(&font_path)?)?;
let handle = doc.add_font(font);

let mut c = Content::new();
c.begin_text();
c.set_font(&handle, 14.0)?;
c.text_position(60.0, 760.0)?;
for line in &lines {
    c.show_glyphs(&handle.glyphs(line));
    c.text_position(0.0, -28.0)?;
}
c.end_text();

let width = handle.measure(lines.last().map_or("", String::as_str), 14.0);

In Python

font = hqf_pdf.Font.from_path(font_path)
handle = document.add_font(font)

content = hqf_pdf.Content()
content.begin_text()
content.set_font(handle, 14.0)
content.text_position(60.0, 760.0)
for line in lines:
    content.show_glyphs(handle.glyphs(line))
    content.text_position(0.0, -28.0)
content.end_text()

width = handle.measure(lines[-1], 14.0)

Ein Absatz, der sich selbst umbricht

In Rust

let flow = TextFlow::new(&handle, 11.0).align(align).leading(15.0);
let lines = flow.break_lines(words.paragraph, box_width);

c.begin_text();
flow.draw(&mut c, &lines, x, top, box_width)?;
c.end_text();

In Python

flow = hqf_pdf.TextFlow(handle, 11.0, align=align, leading=15.0)
lines = flow.break_lines(words.paragraph, box_width)
flow.draw(content, lines, x, top, box_width)

Eine Tabelle, die Seite um Seite weiterläuft

Eine Zeilenhöhe wird nie angegeben: Sie wird an dem Text gemessen, den die Zeile trägt, sobald die Spaltenbreiten bekannt sind. So kann die Tabelle Zeile für Zeile entscheiden, ob die nächste noch passt. Das Einpassen zeichnet nichts: Es liefert die Geometrie zurück, sodass sich eine Tabelle messen lässt, bevor jemand festlegt, wohin sie kommt. Rufen Sie es einmal pro Seite auf, bis es meldet, dass es fertig ist, oder verlangen Sie den ganzen Lauf in einem Aufruf und erhalten Sie eine Platzierung pro Seite.

In Rust

let columns = Columns::new(
    vec![
        ColumnWidth::Fraction(1.0),
        ColumnWidth::Points(46.0),
        ColumnWidth::Points(94.0),
        ColumnWidth::Points(94.0),
    ],
    TABLE_WIDTH,
)?;

let mut table = Table::new(columns);
table.header(1);
table
    .rule(Rule::Frame, Stroke::black(0.8))
    .rule(Rule::HorizontalOther, Stroke::new(0.25, Rgb::gray(0.75)));

let pad = Padding::symmetric(5.0, 4.0);
table.push(
    Row::new()
        .cell(Cell::new(text, 9.0, label).padding(pad))
        .cell(Cell::new(text, 9.0, value).padding(pad).align(Align::Right)),
);

let mut start = 0;
loop {
    let placed = table.fit(TableFrame::new(MARGIN, TOP, TOP - BOTTOM), start)?;

    let mut content = Content::new();
    placed.draw(&mut content)?;

    let mut page = Page::a4();
    page.content = content.into_bytes();
    doc.add_page(page)?;

    match placed.outcome() {
        FitProgress::Done => break,
        FitProgress::BoxFull { next_row } => start = next_row,
        FitProgress::RowTooTall { row } => {
            return Err(format!("row {row} is taller than a page").into());
        }
        outcome => return Err(format!("the table fitted to {outcome:?}").into()),
    }
}

In Python

columns = hqf_pdf.Columns(
    [
        hqf_pdf.ColumnWidth.fraction(1.0),
        hqf_pdf.ColumnWidth.points(46.0),
        hqf_pdf.ColumnWidth.points(94.0),
        hqf_pdf.ColumnWidth.points(94.0),
    ],
    TABLE_WIDTH,
)

table = hqf_pdf.Table(columns)
table.header(1)
table.rule(hqf_pdf.Rule.frame(), hqf_pdf.Stroke(0.8))
grey = hqf_pdf.Rgb.gray(0.75)
table.rule(hqf_pdf.Rule.horizontal_other(), hqf_pdf.Stroke(0.25, color=grey))

pad = hqf_pdf.Padding.symmetric(5.0, 4.0)
table.push(
    hqf_pdf.Row(
        cells=[
            hqf_pdf.Cell(font, 9.0, label, padding=pad),
            hqf_pdf.Cell(font, 9.0, value, padding=pad, align=hqf_pdf.Align.Right),
        ]
    )
)

start = 0
while True:
    placed = table.fit(MARGIN, TOP, TOP - BOTTOM, start)

    content = hqf_pdf.Content()
    placed.draw(content)

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    document.add_page(page)

    if placed.done:
        break
    start = placed.next_row

Wie Ablehnungen zurückkommen

In Rust gibt alles, was ablehnen kann, ein Ergebnis mit dem eigenen Fehlertyp der Bibliothek zurück: ein nicht erschöpfendes Enum mit 186 Varianten, von denen jede genau benennt, was geschehen ist — eine fehlerhafte Schrift, ein fehlerhaftes Bild, keine solche Schrift, keine solche Seite, zwei gleich benannte Felder, etwas, das für den Druck fehlt, etwas, das für die Archivierung fehlt, etwas, das die Konformitätsstufe verbietet, eine Zeile, die höher ist als ihr Kasten, keine Lizenz, eine ungültige Lizenz, eine verschlüsselte Datei. Ein Kunde prüft den genauen Fall statt des Meldungstextes.

Daten von außen — ein PDF, eine Schrift, ein Bild, ein Profil —, die nicht standhalten, sind ein gewöhnliches Ergebnis, als solches zurückgegeben und nie ein Absturz. 21 Panics verbleiben auf Produktionspfaden. Jeder nennt die Invariante, die er einhält, und keiner ist von einem Wert aus erreichbar, den ein Kunde liefert.

In Python kommen dieselben Ablehnungen als Ausnahmen zurück, alle eigenen der Bibliothek unter einer einzigen Klasse, die ein Kunde als Ganzes abfangen kann. Die 2 Layoutfälle — eine Tabellenzeile, die höher ist als der ihr gegebene Kasten, und ein Stapelblock im selben Fall — teilen sich darunter eine eigene Klasse: Eine Umbruchschleife fängt sie über diese gemeinsame Klasse zusammen ab oder jeden für sich.

Neben Ablehnungen gibt es Hinweise. Das Schreiben der Bytes hat eine berichtende Form, die die Bytes und die Liste der Warnungen zurückgibt, die das Dokument über sich selbst hat; die Datei wird in jedem Fall geschrieben und ist gültig, und eine Warnung zeigt auf ein Dokument, das wahrscheinlich nicht das ist, was der Kunde meinte. Eine davon nennt eine Schrift, die entgegen der in der Schriftdatei selbst angegebenen Berechtigung eingebettet wurde: Die Lizenz, unter der die Schrift gekauft wurde, entscheidet die Sache, und der Hinweis legt die Frage dem Kunden vor, der sie entscheidet. Die Prüfung gegen eine Norm geht weiter: Sie liefert alles zurück, was bekanntermaßen zwischen dem Dokument und dieser Norm steht, ohne etwas zu schreiben oder zu ändern.

Was die aktuelle Version abdeckt

Version 1.364.0 der Engine: Schreiben und Lesen von PDF, alle drei Generationen von Schutz auf der Leseseite und AES-256-Verschlüsselung auf der Schreibseite, PDF/A-2, PDF/A-3 und PDF/A-4, PDF/X-4, PDF/UA-1 und PDF/UA-2, Factur-X, vollständiges Tagging, PAdES-Signatur mit vom Kunden gestelltem Signierer, linearisierte Ausgabe, Objektstreams und das Übernehmen von Seiten aus anderen Dateien.

Das Handbuch

Das vollständige Handbuch der Engine — jeder Aufruf, jede Einstellung, jede Falle — wird im direkten Gespräch mit dem Team übergeben.

Wirklich hilft der Teil, der Ihre Frage beantwortet, mit dem Beispiel, das zu Ihrem Fall passt. Der Weg ist also dieser. Sie registrieren sich auf dieser Website, schreiben uns, was Sie vorhaben — eine Rechnung mit ihrem XML, eine Tabelle mit zweitausend Zeilen, ein Bogen, der in Druck geht —, und das Team sendet Ihnen den Teil des Handbuchs, der genau das abdeckt, mit dem Code auf beiden Seiten, Rust und Python.

Sie sprechen mit den Menschen, die die Engine geschrieben haben, und die Antwort ist auf Ihr Projekt zugeschnitten. In der Zwischenzeit decken die 135 mit der Bibliothek gelieferten Beispiele das meiste ab, was sich von ihr verlangen lässt, und jedes läuft so, wie es ist.

Wohin als Nächstes

Alles, was sie auf eine Seite setzt, Gruppe für Gruppe Der andere Weg: das Dokument beim Dienst anfordern Legen Sie ein Konto an und sagen Sie uns, was Sie bauen Fragen Sie uns alles, was diese Seite ausgelassen hat

Die Preise ansehen Die Beispiele ansehen