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 :
<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.
<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>| Attribut | Rôle |
|---|---|
data-pages | Nombre de pages (obligatoire). |
data-src | Adresse 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-formats | JSON [[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-texte | Option : adresse JSON {"pages": ["texte p. 1", …]} → bouton 🔍 Rechercher (accents et majuscules ignorés). |
data-titre | Nom du document, lu par les lecteurs d’écran. |
data-protege | Pas 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-hauteur | Hauteur de la vue (70vh, 600px…). Défaut : min(75vh, 860px). |
data-page | Page 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 :
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| Point | Comment |
|---|---|
| Rendu | Ghostscript (o2switch : 9.27) lancé sans shell, -dSAFER, 25 s au plus, 3 en même temps sur le serveur. |
| Format | WebP 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). |
| Limites | 150 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
| Appel | Rô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:page | Sur 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).
- Une
regionnommé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.