L'API qui crée vos PDF

Votre programme décrit en JSON le document qu'il veut, l'envoie en un appel, et le PDF fini revient dans la réponse.

Résumé

Pensez à commander un gâteau. Vous écrivez ce que vous voulez dessus, vous tendez cette description par-dessus le comptoir, et le gâteau revient par le même comptoir un moment plus tard. Rien d'autre ne se passe, et vous ne voyez jamais la cuisine.

La description, ici, est un texte que votre programme écrit. Il dit ce qui va sur la page : cette phrase à cet endroit, ce tableau en dessous, ce logo dans le coin, ce QR code en bas. Tout ce dont la page a besoin et que le texte ne peut pas contenir — une photographie, un papier à en-tête — voyage à côté.

Cette description s'écrit sous une forme sur laquelle toutes les machines s'entendent, appelée JSON. C'est du texte ordinaire, fait de noms et de valeurs, et il se lit pareil quel que soit le langage dans lequel votre programme est écrit.

Ce qui revient est le document fini, prêt à être envoyé à un client ou à une imprimerie. Il revient dans la réponse à l'appel lui-même, tout de suite.

La réponse, c'est le document. Pas un lien à aller chercher plus tard, pas un numéro de dossier à redemander : les octets du PDF fini reviennent dans la réponse à cet appel-là.

Rien ne s'installe pour appeler cette adresse : votre programme sait déjà envoyer quelque chose par le réseau, et c'est tout ce qu'on lui demande.

Il y a vingt-quatre choses que vous pouvez mettre sur une page : des paragraphes, des tableaux, des photographies, des pages prises dans un autre document, les cinq sortes de code à barres et de code carré, des formes simples, les champs d'un formulaire à remplir, et des liens cliquables. Chacune a ici une page à elle, avec le plus court exemple qui la dessine.

À côté d'elles, soixante clés règlent le document autour de ce qui est tracé : la liste de ce qui va sur les pages, et avec elle le format de la feuille, les polices, ce que le fichier dit de lui-même, la façon dont un lecteur s'y retrouve, les couleurs, et la manière dont tout cela sort. Chacune a elle aussi sa page, si bien que cette partie compte quatre-vingt-quatre pages : une par chose que vous pouvez mettre sur une page, et une par clé.

Deux morceaux, et pourquoi il y en a deux

Le serveur ne crée aucun fichier PDF lui-même. Il lit la description, la vérifie, puis appelle la bibliothèque une instruction à la fois : pose ce paragraphe, commence ce tableau, place cette image ici. C'est la bibliothèque qui écrit le fichier.

Ils sont deux parce qu'ils font deux métiers différents. La bibliothèque sait dessiner et ne sait rien du réseau. Le serveur connaît le réseau — qui appelle, jusqu'à quelle taille une demande peut aller, combien de pages un compte a le droit de faire — et ne sait rien du dessin.

La bibliothèque travaille avec des polices déjà chargées et prêtes à tracer, alors qu'une description qui arrive par le réseau n'en porte que le nom. Transformer ce nom en une police que la bibliothèque sait employer est exactement le travail du serveur, et c'est fait avant que la première lettre ne se pose sur une page.

C'est pour cela que la bibliothèque peut s'acheter et s'utiliser seule, appelée directement depuis un programme écrit en Rust ou en Python, sans serveur et sans qu'aucune description ne voyage. Et c'est pour cela qu'un document sort le même des deux côtés, page pour page : c'est la même bibliothèque qui l'écrit.

Créer un PDF occupe un processeur du début à la fin : chaque demande est traitée par un processus qui n'a qu'elle à faire, et le serveur continue pendant ce temps à répondre à tous les autres.

L'aller-retour, dessiné

  1. Votre propre programme tourne sur vos propres machines
  2. Le serveur à l'adresse que vous appelez
  3. La bibliothèque dans le serveur

Ce qui a été remarqué pendant la création

À côté du document fini, la réponse dit ce qui a été remarqué pendant la création. C'est une remarque, pas un refus : les pages sont bien les pages que vous avez demandées, et une remarque les laisse exactement telles qu'elles sont.

La réponse dit toujours combien il y a eu de remarques, et un zéro est une réponse à part entière : rien n'a été remarqué pendant la création.

Deux choses font l'objet d'une remarque aujourd'hui. La première est quelque chose que votre description a envoyé et qu'aucune page n'a jamais employé — une police, une photographie, une couleur, un calque. Cela a voyagé et cela est entré dans le fichier : le fichier est donc plus lourd que ce que les pages exigeaient.

La seconde est une police qui comprend une note de licence de qui l'a dessinée, disant comment elle peut être transmise. Le document est écrit avec cette police à l'intérieur, et la remarque répète ce que dit la note de licence, pour que vous puissiez la comparer à la licence sous laquelle vous avez acheté cette police. Cette licence est la vôtre et reste chez vous : c'est la seule chose que le fichier ne puisse pas contenir.

Dix remarques au plus reviennent dans la réponse, tandis que le compte dit combien il y en a eu réellement. Il n'existe aucun moyen d'obtenir les autres : le serveur les inscrit toutes dans son propre journal.

Techniquement

Un seul POST /render en multipart/form-data : le document décrit en JSON dans la partie json_data, les fichiers qu'il nomme dans les parties voisines, et en retour soit 200 application/pdf, soit un refus numéroté en texte brut.

Le transport

Une seule adresse, une seule méthode : un POST avec un corps multipart/form-data. La partie nommée json_data tient la description entière en JSON. Toute autre partie est un fichier que la description désigne par le nom de cette partie — un PDF employé comme modèle de page ou importé page par page, une image, un profil ICC, un paquet XMP, le XML d'une facture. Il n'y a pas d'étape d'envoi préalable ni d'identifiant de ressource à garder : une partie ne dure que le temps de l'appel qui l'a transportée.

L'authentification se fait par une clé d'API transmise dans l'en-tête Authorization, que ce site vérifie et convertit en nom de client, transmis dans un en-tête à lui. Un succès répond 200 avec application/pdf et le compte des pages. Un refus répond un code de statut, une phrase en texte brut et x-hqf-refusal : un mot d'une liste fermée qui nomme le type de refus, et c'est lui que lit un programme. Il n'y a pas d'enveloppe à ouvrir ni de tâche à interroger.

Le service que nous faisons tourner ajoute un refus qui lui est propre, et qu'un serveur à vous ne donne jamais : quand tous les documents du mois sont consommés, il répond 429, avec Retry-After qui donne la date à laquelle le mois change. Un serveur à vous ne compte aucun mois.

De quoi un appel et sa réponse sont faits
L'appel qui crée un document, sur un serveur à vous POST /render
Le service que nous faisons tourner, qui prend un appel à lui POST https://hqf-pdf.com/api/v1/render
L'appel qui dit que le service est debout GET /health
La forme dans laquelle le corps est envoyé multipart/form-data
La partie qui contient la description json_data
Toute autre partie un fichier que la description nomme
Le trajet de la clé d'API Authorization: Bearer <key>
Ce que ce site transmet au serveur x-hqf-client: <name>
Ce que contient un succès 200 application/pdf
Combien de pages compte le document fini x-hqf-pages
Combien de choses ont été remarquées pendant la création x-hqf-warnings
Une remarque, répétée une fois par remarque transportée x-hqf-warning
Combien de constats séparent le document des normes demandées x-hqf-findings
Un constat, répété une fois par constat transporté x-hqf-finding
Ce que contient une erreur text/plain
Le mot par lequel un refus nomme sa sorte x-hqf-refusal
La version du service qui a répondu x-hqf-version

L'appel que prend le service que nous faisons tourner, et toutes ses réponses

Le corps, partie par partie

Le corps est un formulaire en plusieurs parties, et chaque partie a un nom.

  • json_data contient la description du document, ses soixante clés. C'est le seul morceau dont le nom est fixé.
  • Toute autre partie est un fichier dans lequel la requête puise, sous le nom que la description lui donne : un PDF posé sous les pages, nommé par templates, une image nommée par un élément image, un profil ICC nommé par output_intent ou par un espace icc, le XML nommé par invoice, un paquet de métadonnées nommé par une image. Ce qu'une partie est découle du JSON qui la nomme, jamais de la partie elle-même.
  • Le corps est gardé en mémoire en entier, et sa taille est plafonnée à 536 870 912 octets — 512 Mio — sauf réglage contraire sur le serveur.
  • Le service que nous faisons tourner plafonne de son côté le corps d'un appel à 536 870 912 octets, soit 512 Mio, et répond 413 en nommant body_too_large au-delà. Les deux plafonds sont deux réglages distincts, si bien qu'un serveur que vous faites tourner peut être réglé plus bas ou plus haut que celui d'au-dessus.

L'en-tête que ce site pose

Le serveur n'authentifie personne : ce site reçoit l'appel, vérifie la clé d'API et nomme le client à qui elle appartient, dans l'en-tête x-hqf-client. Le serveur lit ce nom et crée le PDF selon ce que porte le compte : ses polices, son plafond de pages, ses droits. Une requête qui nomme un client que le serveur ne connaît pas, ou qui n'en nomme aucun, est traitée avec les réglages par défaut. On peut se fier à cet en-tête parce que rien d'autre que ce site ne peut le poser : le serveur écoute sur la boucle locale et rien hors de cette machine ne l'atteint, et ce site réécrit l'en-tête à neuf sur chaque requête qu'il transmet.

Ce que rend une réussite

  • Le code 200, et les octets du PDF comme corps.
  • Content-Type: application/pdf.
  • x-hqf-pages, combien de pages compte le document fini.
  • x-hqf-warnings, combien de choses le moteur a remarquées en écrivant le document, et un x-hqf-warning par remarque transportée.
  • x-hqf-findings, combien de constats séparent le document fini des normes que check a demandé de vérifier, et un x-hqf-finding par constat transporté. Les deux accompagnent une réponse qui contient un document, qu'une norme ait été demandée ou non.
  • Un serveur à vous répète l'en-tête une fois par valeur. Le service que nous faisons tourner ne donne le nom qu'une fois, ses valeurs séparées par des virgules ; la règle pour les découper est sur la page de ce service.

Ce qu'un rendu remarque

Une remarque est quelque chose que le moteur a noté en écrivant un document qu'il a écrit jusqu'au bout : les octets renvoyés sont ceux qu'un rendu sans rien à remarquer aurait renvoyés, et le code de statut reste 200. x-hqf-warnings porte leur nombre et accompagne toute réponse rendue, 0 compris ; une réponse qui ne porte pas cet en-tête vient d'un serveur plus vieux que l'en-tête lui-même.

x-hqf-warning est ensuite répété une fois par remarque transmise, dans l'ordre où le moteur les a faites. Dix au plus, pour mille octets en tout, selon celle des deux limites qui est atteinte la première. La remarque qui dépasse les octets restants est coupée et se termine sur %E2%80%A6, des points de suspension, et les remarques qui la suivent ne figurent que dans le journal du serveur — lequel les garde toutes en entier, au niveau INFO, sous le nom du client pour qui le rendu a été fait. Le compte annonce le nombre entier dans tous les cas, si bien qu'un client qui lit x-hqf-warnings: 50 à côté de dix en-têtes sait exactement où il en est.

Ces deux chiffres sont ce qui garde la réponse livrable. Un serveur frontal plafonne la taille des en-têtes d'une réponse, et un document qui déclare cinquante ressources qu'il ne trace jamais produirait cinquante en-têtes : la réponse entière serait rejetée avant d'atteindre le client, et un document écrit sans faute arriverait comme une panne du service.

  • Une ressource que la demande a déclarée et avec laquelle aucune page n'a rien dessiné — une police, une image, un dessin, un espace de couleur, un état graphique, un dégradé, un motif ou un calque. Elle est écrite dans le fichier et mise à la disposition de chaque page, et aucun flux de contenu ne la désigne. La remarque s'écrit the image Im2 is never drawn with, dans les mots du moteur.
  • Une police incorporée contre ce que son propre marqueur fsType permet : un marqueur qui interdit l'incorporation, un qui demande à entrer en entier là où seules les lettres dessinées sont entrées, ou un qui n'autorise que les images que la police contient là où des contours sont entrés. La remarque nomme la police comme la police se nomme elle-même, et le nom par lequel la requête la choisit — the font Foo (F1) must not be embedded without the owner's permission. Savoir si l'incorporation est licite tient à la licence sous laquelle la police a été achetée, et cette licence est à vous de la lire.
  • Chaque valeur est encodée en pour-cent et se décode comme une adresse internet se décode : chaque octet hors de l'ASCII imprimable s'écrit %XX, et le signe pour-cent lui-même %25, si bien que Café arrive en Caf%C3%A9. Un en-tête ne transporte que de l'ASCII, tandis qu'une ressource est nommée par qui a écrit la requête et qu'une police se nomme elle-même dans sa propre licence : une remarque accepte donc tout ce que ces deux-là contiennent. Une remarque coupée est coupée entre deux caractères, si bien que ce qui arrive se décode, et que ce qu'elle donne est du texte.

La version qui a répondu, et la sonde de santé

GET /health renvoie un 200 et un petit objet JSON : version, le numéro de la version qui a répondu, licensed, si une licence couvre le jour, et faces, le nombre de polices que porte la bibliothèque générale. C'est ce que lit un superviseur ou un répartiteur de charge pour savoir que le service répond, et ce que lit un déploiement pour savoir que la version installée est bien celle qui répond maintenant.

Le même numéro figure sur chaque réponse que le service envoie, dans l'en-tête x-hqf-version : sur un document créé, sur un refus et sur la sonde de la même façon. Le client l'inscrit dans son propre journal à côté de l'appel qu'il a passé, de sorte qu'un document revenu faux est rattaché à la version qui l'a créé ; et après un déploiement, on le lit pour distinguer une instance remplacée d'une instance restée en arrière. Une réponse qui ne porte pas cet en-tête vient d'une version plus ancienne que l'en-tête lui-même. Ce numéro appartient au service : le moteur en porte un qui lui est propre, sur la page de la bibliothèque, et ce site en porte un troisième, au bas de chaque page.

Le modèle

Une requête a un seul niveau supérieur : une liste d'éléments, et à côté les ressources que ces éléments nomment. Les polices, les espaces colorimétriques, les dégradés, les états graphiques, les calques et les dessins sont déclarés chacun une fois sous un nom, et un élément renvoie à ce nom. Une ressource se trouve par son nom, où qu'elle soit déclarée, et tout ce qui compte est écrit — un nom qu'un élément réclame et qu'aucune déclaration ne porte est refusé, avec le nom dans le message.

Les pages sont créées par ce qu'on dessine dessus, elles ne sont pas déclarées d'avance. Un élément dit sur quelles pages il se pose ; le défaut, un tableau vide, veut dire toutes les pages, et c'est ainsi qu'un pied de page ou un filigrane s'écrit une seule fois. Un tableau qui déborde de son cadre se poursuit dans le cadre suivant et crée les pages qu'il lui faut, et les éléments posés sur toutes les pages l'y suivent.

La géométrie est en points typographiques avec l'origine en bas à gauche, comme le veut le format lui-même. Toute coordonnée peut être une expression arithmétique entre guillemets portant sur les dimensions de la page et le numéro de page courant, si bien qu'une marge de droite s'écrit "{page_width} - 56" plutôt qu'un nombre que votre programme aurait dû calculer. Un article peut se nommer lui-même et un autre s'accrocher à son bord, ce qui garde une mise en page juste quand la hauteur d'un bloc n'est connue qu'une fois composé.

Ce qu'une requête tient à côté de ce qu'elle crée

La même requête énonce les métadonnées du document, la norme d'archivage qu'il revendique, l'intention de sortie au regard de laquelle ses couleurs se lisent, la compression de ses flux, le sommaire et les destinations nommées, les fils d'articles, les étiquettes de page, les préférences de lecture que le logiciel de lecture honore, et le XML de facture qu'un document Factur-X contient. Un seul appel produit un fichier fini qui revendique ses normes : il n'y a ni second passage ni outil de retouche.

Les réponses, et ce qu'elles disent

La validation est complète et a lieu avant que rien ne soit dessiné : le serveur refuse une demande plutôt que de produire un document qui aurait perdu quelque chose en silence. Un refus est une phrase qui nomme la clé ou le nom en cause, et elle mérite d'être journalisée mot pour mot.

À côté d'elle se tient x-hqf-refusal, un mot d'une liste fermée : client_name, call_number, form, body_too_large, description, drawing, too_many_pages, needs_a_licence, server. C'est sur lui qu'un programme se branche, la phrase étant écrite pour une personne. Un mot absent de cette liste vient d'un serveur plus récent que cette page.

Les clés inconnues sont ignorées presque partout, ce qui rend une requête écrite pour une version plus récente sans danger à envoyer à une plus ancienne. La seule exception est la forme objet de pages, la règle bâtie sur every, from, to et but : là, une clé que la règle ne connaît pas est refusée par son nom, car une règle qui n'énonce rien couvre tout le document et une clé mal orthographiée ferait silencieusement la même chose. Une clé écrite deux fois dans le même objet est refusée par son nom. Les combinaisons qui se contrediraient — une matrice avec une rotation, un lien qui déclare à la fois une cible courte et une action complète, une cellule de tableau qui contient deux choses — sont refusées par leur nom également.

Une page que le document n'a pas est refusée partout où une clé en nomme une — un signet, une destination nommée, la zone d'un fil d'articles — et le message nomme cette page dans la numérotation qu'a employée la requête : demandez la page neuf d'un document de cinq pages, le message dit page neuf.

Ce site attend le document 30 secondes, pas davantage. Au-delà, l'appel revient sous le statut 503 avec une phrase disant que le service n'a pas répondu. Le temps que prend un document qui vous appartient n'est publié nulle part : mesurez-le sur vos propres pages, sur la machine qui les traitera.

Toutes les réponses du service, par leur numéro
200 Le PDF est le corps. À côté de lui se tiennent le compte des pages et ce qui a été remarqué pendant la création : un compte, et un en-tête par remarque transportée.
400 La requête doit être corrigée et renvoyée ; le corps est une phrase de texte simple. Cas connus : le JSON ne se lit pas ; la partie `json_data` est absente ; une police nommée n'est déclarée nulle part ; une coordonnée ne s'analyse pas ; un lien ou un signet mène à une page que le document n'a pas, nommée dans la numérotation qu'emploie la requête elle-même ; une norme déclarée et un réglage que cette norme écarte se contredisent ; un niveau de compression sort de 1 à 9 ; un modèle de page fourni n'est pas un PDF qui se lit.
402 La requête demande quelque chose que seule une clé de licence couvre, sous `x-hqf-refusal: needs_a_licence`. La phrase nomme ce qui a été demandé et dit qu'une clé de licence le porte. Tous les cas : du texte composé dans une police sans contour d'où tracer les glyphes — les quatorze polices standard, une police dont les glyphes sont des dessins, un programme de type 1 ; une page importée d'un autre document qui montre plus de dix mille mots à elle ; une page importée dont les mots ne peuvent pas être comptés du tout ; une déclaration d'accessibilité, ou d'archivage au niveau qui repose sur le fait de dire ce que les marques d'une page représentent ; une destination qui mène à un élément de l'arbre de structure. Les trois derniers viennent d'une copie gratuite qui trace chaque glyphe comme une forme : le document n'a aucun arbre de structure sur lequel ils pourraient reposer.
413 Le corps de la requête dépasse la taille que le serveur accepte, ou le document dépasse le plafond de pages du serveur ou du compte. La phrase nomme la taille ou le plafond.
500 L'écriture du PDF ou du magasin de polices n'a pas abouti. C'est du côté du service, non de la requête.

Schéma de la requête

Toutes les clés d'une requête, avec leur type, leur caractère obligatoire ou non, et ce qu'elles valent quand on les laisse de côté. Chaque chiffre a été relevé sur les sources du serveur et vaut pour la version en production.

La plus petite requête qui crée un PDF

Une police déclarée, un élément, une ligne de texte. Enregistrez, envoyez, et un PDF d'une page revient.

{
  "standard_fonts": [{ "name": "sans", "face": "helvetica" }],
  "items": [
    {
      "type": "text",
      "rect": { "llx": 56, "lly": 700, "urx": "{page_width} - 56", "ury": 780 },
      "content": ["Invoice 2026-014"],
      "font": "sans",
      "font_size": 24
    }
  ]
}

Le même appel, écrit trois fois

Aucun des trois n'est une bibliothèque à installer : le serveur répond par le réseau, donc n'importe quel langage capable d'envoyer un formulaire l'appelle. En voici trois — un terminal, Python et JavaScript.

Copiez celui des trois qui correspond à vos outils. Chacun envoie la description et un fichier qu'elle emploie, et écrit la réponse directement sur le disque.

Ce que créent les bibliothèques Rust et Python

Depuis un terminal

Une partie contient la description, une partie par fichier qu'elle emploie. Le nom d'une partie est le nom sous lequel la description appelle ce fichier.

# The service we run takes a call of its own:
# POST https://hqf-pdf.com/api/v1/render described on
# https://hqf-pdf.com/en/api/pdf-api-endpoint/
curl -X POST https://your-server/render \
  -H "Authorization: Bearer $HQF_PDF_KEY" \
  -F "json_data=@invoice.json;type=application/json" \
  -F "letterhead.pdf=@letterhead.pdf" \
  -o invoice.pdf

Depuis Python

La clé d'API vient de l'environnement, et la réponse est le PDF lui-même : écrivez donc le corps directement dans un fichier. Le nombre de pages figure sur toute réponse qui rapporte un document.

import json
import os
import pathlib

import requests

KEY = os.environ["HQF_PDF_KEY"]
LETTERHEAD = pathlib.Path("letterhead.pdf")

description = {
    "standard_fonts": [{"name": "sans", "face": "helvetica"}],
    "items": [
        {
            "type": "text",
            "rect": {"llx": 56, "lly": 700, "urx": "{page_width} - 56", "ury": 780},
            "content": ["Invoice 2026-014"],
            "font": "sans",
            "font_size": 24,
        }
    ],
}

# The service we run takes a call of its own: POST https://hqf-pdf.com/api/v1/render
# described on https://hqf-pdf.com/en/api/pdf-api-endpoint/
answer = requests.post(
    "https://your-server/render",
    headers={"Authorization": f"Bearer {KEY}"},
    files={
        "json_data": ("request.json", json.dumps(description), "application/json"),
        "letterhead.pdf": ("letterhead.pdf", LETTERHEAD.read_bytes()),
    },
    timeout=120,
)
answer.raise_for_status()
pathlib.Path("invoice.pdf").write_bytes(answer.content)
print(answer.headers["x-hqf-pages"], "pages")

Depuis JavaScript

Un corps de formulaire et le fetch standard, exécutés par Node. La clé d'API vient de l'environnement et le modèle de page d'un fichier posé à côté du programme, et un refus arrive sous la forme d'une phrase en texte brut.

import { readFile, writeFile } from "node:fs/promises";

const key = process.env.HQF_PDF_KEY;
const letterhead = new Blob([await readFile("letterhead.pdf")]);

const description = {
  standard_fonts: [{ name: "sans", face: "helvetica" }],
  items: [
    {
      type: "text",
      rect: { llx: 56, lly: 700, urx: "{page_width} - 56", ury: 780 },
      content: ["Invoice 2026-014"],
      font: "sans",
      font_size: 24,
    },
  ],
};

const body = new FormData();
const asJson = JSON.stringify(description);
body.append("json_data", new Blob([asJson], { type: "application/json" }));
body.append("letterhead.pdf", letterhead, "letterhead.pdf");

// The service we run takes a call of its own:
// POST https://hqf-pdf.com/api/v1/render
// described on https://hqf-pdf.com/en/api/pdf-api-endpoint/
const answer = await fetch("https://your-server/render", {
  method: "POST",
  headers: { Authorization: `Bearer ${key}` },
  body,
});
if (!answer.ok) {
  throw new Error(await answer.text());
}
await writeFile("invoice.pdf", new Uint8Array(await answer.arrayBuffer()));

Les clés d'une requête

Soixante clés se tiennent au premier niveau d'une requête, et une seule est obligatoire. Toutes les autres prennent par défaut la valeur de la colonne d'à côté, si bien qu'une requête déclare ce dont elle a besoin et rien d'autre. Chaque clé mène à sa propre page.

Toutes les clés JSON d'une requête, au premier niveau
Clé JSON Type Défaut À quoi ça sert
items tableau obligatoire Tout ce qui est dessiné sur les pages, dans l'ordre où c'est dessiné. C'est la seule clé qu'une requête ne peut pas omettre.
page objet 595.276 × 841.89 La feuille sur laquelle chaque page est coupée, en points, sauf si une page nomme la sienne.
page_sizes tableau [] Une feuille à elle pour une page numérotée.
page_boxes tableau [] Les boîtes de rognage, de fond perdu, de coupe et de dessin d'une page, ce qu'une imprimerie lit avant tout le reste.
page_turns tableau [] Dans quel sens une page est présentée à celui qui ouvre le fichier.
page_tab_orders tableau [] L'ordre dans lequel le clavier parcourt les champs d'une page.
page_shows tableau [] Comment une page arrive, et combien de temps elle reste, quand le logiciel de lecture montre le document en plein écran.
supplied_pdfs objet La façon dont les PDF fournis avec la demande sont lus : jusqu'où un de leurs flux a le droit de se déplier.
structure objet Ce dont le document dit être fait, dans l'ordre de lecture, pour qu'un programme le lise comme une personne le lirait plutôt que dans l'ordre où l'encre est tombée.
accessible chaîne La norme d'accessibilité que le document déclare, vérifiée contre ce qu'il contient vraiment.
simple_fonts tableau [] Une police atteinte par des codes d'un octet, ajustés à un texte donné : une page plus légère, et un écartement des mots qui a un code à atteindre.
attachments tableau [] Les pièces jointes du document, à côté de ses pages.
collection objet Comment un logiciel de lecture dispose les pièces jointes en portefeuille : les colonnes, l'ordre des lignes, et le fichier ouvert en premier.
page_files tableau [] Les pièces jointes qu'une page revendique comme siennes.
page_metadata tableau [] La fiche d'identité qu'une page contient, à côté de celle du document.
tilings tableau [] Une case répétée pour remplir une forme : hachure, tissage, fond.
fonts tableau [] Les polices transportées dans la requête en base64, chacune sous un nom que les éléments appellent, avec les caractères qu'elles gardent et ce qu'elles dessinent pour un caractère dont elles n'ont pas le glyphe.
type1_fonts tableau [] Polices de type 1, envoyées de même.
standard_fonts tableau [] L'une des quatorze polices que tout logiciel de lecture possède déjà, sous un nom de votre choix.
font_variants tableau [] Une police déclarée avec les ligatures, les petites capitales, les chiffres elzéviriens ou le crénage activés.
type3_fonts tableau [] Police dont les glyphes sont des dessins, non des contours.
font_chains tableau [] Deux polices ou plus essayées dans l'ordre : un glyphe qui manque à la première est pris dans la suivante.
templates objet Les PDF fournis posés sous la première page, sous les pages du milieu et sous la dernière.
renumber tableau [] Où la numérotation des pages repart, dans quel style, derrière quel préfixe.
bookmarks tableau [] Le sommaire que le logiciel de lecture ouvre à côté de la page, imbriqué aussi profond que vous voulez.
destinations tableau [] Des endroits nommés du document qu'un lien ou une action peut viser.
articles tableau [] Des fils de lecture qui mènent le lecteur d'une colonne à la suivante.
document_parts objet L'arbre des parties qu'un document PDF 2.0 déclare, chacune revendiquant une plage de pages et tenant des valeurs nommées.
private_data objet Ce qu'un programme laisse dans le document pour lui-même, rangé sous son propre nom. Aucun logiciel de lecture ne le montre.
page_private_data tableau [] Les mêmes, laissées sur une page numérotée plutôt que sur le document.
metadata objet Titre, auteur, sujet, mots-clés, le logiciel dans lequel il a été écrit, producteur, dates de création et de modification, état de recouvrement, et schémas de votre cru.
information_dictionary objet Si le fichier garde sa table d'entrées à côté de son paquet de métadonnées, ou dit ce qu'il est dans le seul paquet.
archive chaîne La norme d'archivage que le fichier revendique : `pdfa3b` ou `pdfa4`.
protection objet Les mots de passe sous lesquels le document est verrouillé, et ce que le logiciel de lecture est prié d'autoriser une fois qu'il est ouvert.
invoice objet Le XML de facture contenu dans le document, avec son profil, sa version, sa relation et sa date.
reading objet Comment le logiciel de lecture est prié d'ouvrir le fichier : quel panneau, quelle disposition, quelle page, quel grossissement, et quoi envoyer à une imprimante.
base_uri chaîne L'adresse contre laquelle un lien relatif est résolu.
version chaîne celle du moteur La version de PDF que le fichier déclare : de `1.4` à `1.7`, ou `2.0`.
compression objet Si les flux sont compressés, à quel niveau, et si les petits objets voyagent groupés.
first_page_first objet Si le fichier est écrit première page d'abord, pour que le logiciel de lecture montre la page 1 pendant que le reste arrive encore.
output_intent objet sRGB Le profil de couleur contre lequel les couleurs du fichier doivent être lues.
images tableau [] Ce qu'une image fournie dit d'elle-même, et la façon dont elle est lue : ses masques, ses échantillons transparents, son orientation et son profil.
color_spaces tableau [] Séparations, palettes indexées, Lab, gris et RVB calibrés, et espaces fondés sur un profil, chacun sous un nom qu'une couleur peut appeler.
shadings tableau [] Les dégradés axiaux et radiaux, chacun sous un nom qu'un remplissage peut appeler.
graphics_states tableau [] Des états nommés contenant les opacités, le mode de fusion, un masque, et ce que demande une presse : la surimpression, l'intention, la courbe de transfert et la trame.
layers tableau [] Des calques nommés que le logiciel de lecture peut allumer et éteindre, et qui disent s'ils s'impriment.
drawings tableau [] Des dessins vectoriels nommés, c'est-à-dire ce qu'un bouton poussoir montre comme icône.
transparency objet L'espace de fusion dans lequel travaille le groupe de la page, et s'il est isolé ou en défonce.
page_units tableau Le nombre de points que vaut une unité de page, pour une feuille plus grande que les 14 400 points dans lesquels un PDF se mesure.
page_review_marks tableau Les formes qu'une page ajoute par-dessus ce qu'elle dessine : une note, un tampon, une forme tracée à la main.
page_triggers tableau Ce qu'une page déclenche quand le logiciel de lecture y arrive, et quand il la quitte.
print chaîne La norme d'impression que le document revendique, et pour laquelle il est refusé s'il la casse.
check tableau Les normes contre lesquelles le document fini est mesuré, la réponse revenant à côté du fichier.
page_spaces tableau Ce que veulent dire les nombres bruts d'une page, espace de couleur par espace de couleur, et comment ses marques se combinent.
page_separations tableau De quelle plaque d'une feuille séparée une page est, et l'encre dans laquelle elle s'imprime.
page_output_intents tableau L'appareil pour lequel les couleurs d'une page sont dites, quand la couverture et l'intérieur ne s'impriment pas sur le même papier.
layer_rules tableau Un nom sur lequel des éléments sont dessinés et qui vaut pour plusieurs calques à la fois, avec la règle qu'un logiciel de lecture applique pour décider s'il les montre.
layer_configurations tableau Les jeux nommés d'états de calques que le logiciel de lecture propose à côté de celui sous lequel le document s'ouvre.
layer_families tableau Les calques dont le logiciel de lecture ne montre qu'un à la fois : en montrer un éteint les autres.
carried_facts tableau [] Des listes nommées de vos propres données, chacune accrochée à un passage d'encre par l'élément qui la nomme. Aucun logiciel de lecture ne les montre.

Les quatre-vingt-quatre pages de cette section

Une page par élément et par clé qu'une demande peut porter, classée sous la question à laquelle elle répond. Chacune dit ce qu'est la chose, ce qu'elle fait techniquement, le schéma de la demande qu'elle accepte, et montre une demande entière qui l'utilise.

Ce qu'une requête crée

Vingt-quatre choses se posent sur une page, et chacune a ici sa page : ce qu'elle est, ce qu'elle fait techniquement, le schéma de la requête qu'elle prend, et une requête entière qui la montre.

Texte
Les tableaux
Images et pages importées
Les codes-barres et les codes carrés
Formes
Champs de formulaire
Navigation

Ce qu'une requête règle

Soixante clés se tiennent au premier niveau d'une requête et règlent le document autour de ce qui est dessiné : la feuille, les polices, l'identité du fichier, la façon dont un lecteur y circule, la couleur, et le rendu lui-même.

La feuille, et ce qu'on pose dessous
Les polices
Le document dans son ensemble
S'y retrouver
La couleur et la façon dont elle est rendue
Ce qui est dessiné, et comment cela sort

Les formes dont chaque clé est faite

Une poignée d'objets reviennent partout dans le format. Ils sont écrits une fois ici, et chaque page qui en emploie un le nomme avec ces mots.

Les objets dont les clés JSON sont faites
rect Quatre coordonnées — `llx`, `lly`, `urx`, `ury`. L'origine est en bas à gauche de la feuille et l'axe vertical monte, ce qui est la convention du format lui-même.
coordonnée Un nombre, ou une expression entre guillemets sur `+ - * / ( )` et les variables `{page_width}`, `{page_height}`, `{current_page}`, `{total_pages}`, `{llx}`, `{lly}`, `{urx}`, `{ury}`. Une expression s'imbrique jusqu'à cent niveaux, ce qui permet à un article de se caler sur la largeur de la page sans que le client calcule quoi que ce soit.
color Un nombre pour un gris, trois pour le rouge, le vert et le bleu, quatre pour les quatre encres d'imprimerie, tous de 0 à 1. Aussi `{"gray": n}`, et `{"space": "name", "components": …}` pour un espace que la requête a déclaré.
stroke Une `width`, et facultativement une `color`, un motif `dash` avec sa phase, un `cap` et un `join`.
pages Les pages, numérotées à partir de un, sur lesquelles un élément est dessiné. Le défaut, un tableau vide, le dessine sur toutes les pages, et c'est ainsi qu'un pied de page s'écrit une seule fois.
layer Le calque déclaré auquel un élément appartient, et que le logiciel de lecture allume et éteint.
id / relative_to Un élément se nomme lui-même avec `id` ; un autre se place contre le bord `top` ou `bottom` de celui-là avec un `offset`, si bien qu'un paragraphe suit un tableau dont personne ne connaissait la hauteur d'avance.
transform / rotate Six nombres pour une matrice, ou un nombre de degrés dans le sens inverse des aiguilles d'une montre autour du centre du rectangle. Un élément énonce l'un ou l'autre.

Comment une requête est lue

  • Une clé que le serveur ne connaît pas est ignorée, si bien qu'une requête écrite pour une version plus récente est traitée sans encombre par une plus ancienne.
  • Une clé écrite deux fois dans le même objet est refusée, et le message nomme la clé.
  • Un choix qui n'a aucune valeur propre s'écrit en chaîne nue — "center", "pdfa4". Un choix qui en a une est un objet à une seule clé, qui nomme la variante — {"points": 12}, {"page": 3}.
  • Une clé facultative absente et un null explicite se lisent de la même façon, ce qui permet à un sérialiseur d'écrire l'une ou l'autre.
  • La même description, envoyée deux fois, rend deux fois les mêmes octets, sauf aux deux endroits où le schéma en décide autrement : un passage qui demande le moment du rendu lit l'horloge au moment où la page s'écrit, et un bloc protection qui ne déclare aucune clé à lui est verrouillé sous trente-deux octets tirés de la machine. Partout ailleurs, l'identifiant du fichier est une empreinte de ce qui a été écrit : deux rendus se comparent donc comme deux fichiers.

Les chiffres auxquels le service se tient

Chaque chiffre, et ce qu'il plafonne
Le corps d'une requête, sur un serveur qui vous appartient 536 870 912 (512 Mio)
Le corps d'une requête adressée au service que nous faisons tourner 536 870 912 (512 Mio)
Combien de temps le service que nous faisons tourner attend un document 30 secondes
Profondeur d'imbrication d'une expression 100
Entrées d'une palette indexée 256
Niveau de compression 1 – 9
Correction d'erreur d'un code Aztec 0 – 90 %
Colonnes d'un code PDF417 1 – 30
Correction d'erreur d'un code PDF417 0 – 8
Polices en chaîne 2 ou plus
Remarques qu'une réponse transporte 10
Octets que ces remarques totalisent 1 000
Pages du modèle du milieu 1
Jusqu'où un flux d'un PDF fourni se déplie 1 073 741 824
Caractères du nom d'une police gardée 64
Pages d'un document ce que comprend votre forfait

Les questions qu'on pose en premier

Garde-t-on quelque chose de mon document ?

Non, pas les pages. Le PDF fini repart dans la réponse à votre appel, et il n'est jamais écrit sur un disque en chemin.

La description que vous avez envoyée, et tout fichier envoyé avec elle, ne sont gardés que le temps du rendu, et seulement dans la mémoire de la machine. Ni l'une ni l'autre n'est écrite sur un disque, et les deux disparaissent au moment où les pages partent.

Deux choses sont écrites sur le disque, et deux seulement. La première, les polices. Si votre compte a le droit d'envoyer ses propres polices, alors une police que le rendu a réellement employée est gardée dans un dossier qui appartient à ce compte, pour que vous n'ayez jamais à l'envoyer une seconde fois — dès lors, votre description se contente de la nommer. Une police envoyée mais qui n'a servi à dessiner nulle part n'est pas gardée, et un rendu qui a échoué ne garde rien du tout. Un compte qui dessine avec les polices déjà présentes sur le serveur ne garde rien non plus.

La seconde, une ligne levée quand le serveur casse de son propre côté, pour que quelqu'un ici soit réveillé. Elle nomme la sorte de panne, le compte, le numéro que votre réponse citait et le moment, et rien de ce que votre description a choisi. Elle attend dans un petit fichier jusqu'à ce que ce site l'ait prise, et le quitte dès qu'il l'a fait.

Rien de ce qui touche à la facture ne voyage depuis le serveur. Ce site compte le rendu sur la réponse qu'on lui rend et écrit une ligne à lui : le nom du compte, un identifiant qui désigne ce seul rendu, le moment où il a eu lieu, et le nombre de pages sorties. Rien de ce qui est écrit sur ces pages ne part avec elle.

Le serveur tient un journal, comme tout programme sur une machine. Il écrit une ligne pour chaque document qui sort, qui donne le nom du compte, le nombre de pages sorties et le temps que ça a pris. Il en écrit une autre quand un rendu mentionne quelque chose qu'il n'a ensuite jamais employé — une police, une image, une couleur que rien n'a choisie — et qui donne le nom du compte et la remarque. Les pages reviennent dans tous les cas : c'est une remarque, pas un refus.

Si vous faites tourner le serveur sur vos propres machines, rien de tout cela ne nous parvient. Le compte rendu s'allume en lui donnant une adresse où envoyer, et un serveur à qui on n'en a donné aucune n'envoie rien nulle part.

Comment appelle-t-on le serveur, et sous quelle forme ?

Une adresse prend le travail, et la demande lui est envoyée sous forme de formulaire. Une partie de ce formulaire contient la description du document, écrite en texte ordinaire. Chaque autre partie est un fichier sur lequel le document s'appuie. Ce qui revient, c'est le PDF lui-même.

Tout ce qui sait envoyer un formulaire par le réseau peut l'appeler, quel que soit le langage. Le tableau ci-dessus donne l'adresse, la forme et la réponse au mot près, et le petit exemple plus bas est une demande entière qui marche.

Qu'apporte ceci face à une bibliothèque PDF gratuite ?

Une grande quantité de documents s'écrit chaque jour avec des bibliothèques PDF gratuites, et plusieurs d'entre elles font très bien ce qu'elles se sont donné pour tâche. Ce qui se vend ici est autre chose : un seul ensemble qui couvre déjà tout le terrain, et quelqu'un qui en répond.

Le terrain est vaste. Du texte qui s'écoule, des tableaux qui se poursuivent sur autant de pages qu'il leur en faut, des images, des couleurs d'imprimerie, des codes-barres, des formulaires à remplir, des fichiers faits pour s'ouvrir encore dans des dizaines d'années, des fichiers faits pour être lus à voix haute à quelqu'un qui ne voit pas la page, et la place réservée à un sceau. Une seule chose à apprendre, une seule chose à tenir à jour, et une seule adresse où écrire quand une page ne sort pas comme vous l'attendiez.

La vérification vient de l'extérieur. Il existe un contrôleur gratuit qui s'appelle veraPDF, dont tout le métier est d'ouvrir un fichier et de dire s'il suit les règles publiées, et tout document d'archivage montré sur ce site passe par lui. Nous n'en possédons aucune part, et il ne sait rien de qui a écrit le fichier qu'il a devant lui.

Le même document est écrit de trois façons — un programme Rust, un programme Python, et une demande au serveur — puis les trois sont relancées et comparées. Là où elles sortent pareil à l'octet près, c'est écrit à côté ; là où elles sortent pareil à l'œil mais pas à l'octet, c'est écrit aussi.

Et il y a un contrat, une société, et quelqu'un à qui écrire. Assembler soi-même plusieurs morceaux gratuits est une bonne façon de travailler, et c'est aussi un travail que quelqu'un doit faire, puis continuer à faire : quand deux d'entre eux ne s'accordent pas, c'est à vous de chercher pourquoi. Ici, c'est à nous.

La bibliothèque achetée d'un coup reste la vôtre : payée une fois, installée autant de fois que vous voulez, et elle ne s'arrête pas de marcher le jour où quelque chose se termine.

Faut-il installer quelque chose ?

Avec un abonnement, non. Vous appelez une adresse par le réseau et les pages reviennent. Rien ne s'installe chez vous et rien n'est à tenir à jour.

Si vous achetez le serveur, c'est un seul programme à lancer sur vos propres machines, avec une poignée de réglages : où vivent ses polices, où vit sa clé de licence, et jusqu'à combien de pages un document peut aller. Il écoute sur la machine elle-même et se place derrière le serveur frontal que vous faites déjà tourner, quel qu'il soit.

Si vous achetez la bibliothèque seule, elle entre dans votre programme comme n'importe quelle autre pièce, depuis Rust ou depuis Python. Pas de serveur, pas de réseau, rien à faire tourner à côté.

Comment suis-je facturé ?

Au document. Chaque rendu est déclaré une fois, avec le nombre de pages qu'il a créées, et un mois de rendus s'additionne en une seule facture. Un document compte pour un, quel que soit le nombre de pages qui en sortent : le nombre de pages est consigné à côté du rendu et n'est jamais facturé.

Un rapport qui n'a pas pu partir tout de suite n'est pas perdu : il attend et part plus tard. Et un rapport qui arrive deux fois n'est compté qu'une fois, parce que chaque rendu a un identifiant à lui.

Quels langages de programmation peuvent l'appeler ?

Tous. La demande est du texte ordinaire envoyé par le réseau : tout ce qui sait faire cela sait demander un document, c'est-à-dire tous les langages d'aujourd'hui.

La bibliothèque du dessous est écrite en Rust et s'appelle tout aussi bien depuis Python, ce dont se sert une équipe qui achète la bibliothèque seule.

Que fait la version gratuite ?

Elle crée des documents, et elle signe son travail. Chaque page qu'elle produit sort avec un filigrane, et chaque lettre de ces pages est tracée comme une forme au lieu d'être écrite comme du texte : les pages ont la bonne apparence, et on ne peut rien en extraire.

Quelques opérations demandent une clé de licence. Une copie gratuite à qui l'on en demande une refuse, le dit clairement, et nomme la clé de licence qui la couvre : composer du texte dans l'une des quatorze polices que tout logiciel de lecture porte déjà ou dans l'un des deux anciens types de police, et reprendre d'un autre document une page qui contient plus de dix mille mots à elle. Une copie gratuite ne compose du texte que dans une police qui donne un glyphe à tracer : une police que votre requête transporte, ou une police que le service détient déjà.

Quelles règles sont vraiment contrôlées, et par qui ?

Les fichiers faits pour rester lisibles pendant des années, et ceux faits pour être lus à voix haute à quelqu'un qui ne voit pas la page, passent par veraPDF, le contrôleur gratuit cité plus haut, et il les accepte. Il est tenu par l'Open Preservation Foundation et la PDF Association, et nous ne possédons ni l'une ni l'autre.

Un fichier destiné à une presse d'imprimerie doit satisfaire quatre exigences avant qu'un seul octet soit écrit, et un fichier auquel il en manque une est refusé plutôt qu'écrit. La page des normes d'impression nomme les quatre.

Comment savoir si le service répond ?

Il existe une seconde adresse dont le seul métier est de le dire. Elle ne crée rien, ne coûte rien à interroger, et répond tant que le service est debout.

Compter vos documents ne retarde jamais un rendu. Les pages reviennent d'abord, et le comptage part de son côté ensuite.

Où aller ensuite

Tout ce que la bibliothèque met sur une page Tout ce que le service garde, en entier Ce qui est détenu sur vous, et pour combien de temps Des fichiers faits pour s'ouvrir encore dans des dizaines d'années Des fichiers qu'un imprimeur passe sans poser de question

Voir les prix Voir les exemples