Aller au contenu
Aubui · Visionneuse PDF
Composants

Visionneuse PDFNouveau

Lire un PDF sans rien télécharger d’autre que les pages qu’on regarde. Le serveur rend chaque page en image (Ghostscript, WebP) ; la visionneuse les affiche à la demande, avec zoom, pincement, plein écran et recherche. Aucun pdf.js, aucune bibliothèque tierce.

Essayer

C’est le composant réel ; ici les « pages » sont dessinées dans la page de doc (SVG) au lieu d’être rendues par un serveur. Pince pour zoomer sur téléphone, double-tape, ou Ctrl + molette.

Installer

Rien à charger à la main : aubui.js récupère aubui-pdf.js (≈ 8 Ko compressé, gardé un an en cache) seulement si la page contient un [data-aubui-pdf]. Sur une page sans aubui.js :

HTML
<script src="https://ui.aubota.xyz/js/aubui-pdf.js" defer></script>

Utilisation déclarative

Le site donne le nombre de pages, le format des pages et l’adresse d’une page ; la visionneuse fait le reste.

HTML
<div data-aubui-pdf
     data-pages="12"
     data-formats='[[595,842]]'
     data-src="/support/c42/f_9a1b/<jeton>/page/{n}/{taille}"
     data-texte="/support/c42/f_9a1b/<jeton>/texte"
     data-titre="Module 1 — Les bases"
     data-protege></div>
AttributRôle
data-pagesNombre de pages (obligatoire).
data-srcAdresse d’une page : {n} = numéro (1…), {taille} = vignette (240 px), ecran (1100 px) ou zoom (1800 px). La visionneuse choisit la taille selon l’écran et le zoom.
data-formatsJSON [[largeur, hauteur], …] en points, une entrée par page — ou une seule si toutes sont pareilles. Sert à réserver la place des pages avant leur chargement (rien ne saute).
data-texteOption : adresse JSON {"pages": ["texte p. 1", …]} → bouton 🔍 Rechercher (accents et majuscules ignorés).
data-titreNom du document, lu par les lecteurs d’écran.
data-protegePas de clic droit, de glisser-déposer ni d’appui long « Enregistrer l’image » sur les pages (contenus payants). Ce n’est pas une protection absolue : c’est le serveur qui décide qui voit quoi.
data-hauteurHauteur de la vue (70vh, 600px…). Défaut : min(75vh, 860px).
data-pagePage affichée au départ.

Côté serveur : PdfPages

Classe hors web src.aubota.xyz/php/pdf/PdfPages.php. Le site vérifie d’abord l’accès et résout lui-même le chemin du PDF (jamais un chemin reçu dans l’adresse), puis :

PHP
require_once __DIR__ . '/../src.aubota.xyz/php/pdf/PdfPages.php';

$pdf = new PdfPages($cheminVerifie);           // refuse ce qui ne commence pas par %PDF-
$pdf->nombrePages();                           // pour data-pages
$pdf->formatsCompacts();                       // pour data-formats
$pdf->servirImage($n, $taille, 'private, no-store'); // dans la route {n}/{taille}
echo json_encode(['pages' => $pdf->textes()]);   // dans la route data-texte
PointComment
RenduGhostscript (o2switch : 9.27) lancé sans shell, -dSAFER, 25 s au plus, 3 en même temps sur le serveur.
FormatWebP si GD sait l’écrire (une page A4 ≈ 25-50 Ko), sinon JPEG écrit par Ghostscript.
Cache~/.aubota/cache/pdf/<clé>/ hors web (0700). Un PDF remplacé change de clé. PdfPages::menage(30) efface ce qui n’a pas servi depuis 30 jours (lancé tout seul de temps en temps).
Limites150 Mo par PDF, 500 pages servies, 5000 px de haut au plus.
PDF piégéUn PDF ne peut lire aucun autre fichier du serveur (testé : /etc/passwd refusé) ; un PostScript renommé en .pdf est refusé avant Ghostscript.

API window.AubuiPdf

AppelRôle
mount(el, options?)Monte une visionneuse (options = mêmes noms que les data-* ; src peut être une fonction (n, taille) → adresse, textes un tableau). Renvoie l’instance.
scan(racine?)Monte toutes les [data-aubui-pdf] (contenu injecté après coup).
instance.aller(n) · page() · pages()Aller à une page, page courante, nombre de pages.
instance.zoom(z?)Lit ou règle le zoom (1 = largeur ajustée, jusqu’à 4).
instance.pleinEcran() · detruire()Bascule le plein écran ; démonte.
Évènement aubui:pdf:pageSur l’élément, à chaque changement de page : detail = { page, pages }.

Réseau (3G / 4G)

  • Seules les pages proches de l’écran sont demandées ; au loin (plus de 6 pages), elles sont libérées pour ménager la mémoire du téléphone.
  • La place de chaque page est réservée dès le départ : la lecture ne « saute » pas pendant le chargement.
  • En zoomant, l’image plus nette remplace l’ancienne une fois arrivée (l’ancienne reste affichée en attendant).
Accessibilité
  • Une region nommée (« Document : … »), boutons étiquetés, numéro de page annoncé (aria-live).
  • Clavier : ← → pages, + − 0 zoom, Début / Fin, Échap quitte le plein cadre ; champ « page » pour sauter directement.
  • « Réduire les animations » respecté (pas de défilement doux, pas d’ondulation pendant le chargement).
  • Une page qui n’arrive pas affiche « Réessayer » au lieu d’un trou.