Aller au contenu
100 % local · 0 Ko téléversésCompresser un PDF

Traitement PDF côté client : comment fonctionnent les outils PDF locaux au navigateur

Un outil PDF côté client fait le même travail qu'un serveur le ferait, mais dans le navigateur de l'utilisateur. Cette page s'adresse aux développeurs et administrateurs IT qui veulent comprendre l'architecture : quelles APIs du navigateur sont impliquées, quelles bibliothèques font le travail lourd, où va réellement le fichier et quelles sont les limites honnêtes. IXPDF est l'exemple en cours, mais le modèle s'applique à tout outil PDF local au navigateur.

Le pipeline

De l'entrée du fichier au téléchargement, sans serveur

Le flux de bout en bout pour une opération PDF côté client est :

  1. Entrée du fichier. L'utilisateur dépose un fichier dans une zone de dépôt. Le navigateur donne à la page un objet File (un pointeur vers le fichier sur disque, pas les octets eux-mêmes).
  2. Lecture en mémoire. La page appelle file.arrayBuffer() pour lire les octets dans un ArrayBuffer dans la mémoire de la page. C'est le seul point où les octets du fichier existent dans la page ; ils ne sont pas encore dans un worker.
  3. Validation. La page vérifie le type de fichier (magic bytes, extension) et la taille avant de faire quoi que ce soit. Les fichiers invalides échouent rapidement sur le thread principal et n'atteignent jamais le worker.
  4. Transfert vers un Web Worker. La page envoie l'ArrayBuffer à un worker, en utilisant un transfert transferable pour que les octets se déplacent (sans copie) vers le heap du worker. Le thread principal n'a plus accès au buffer.
  5. Traitement dans le worker. Le worker appelle une bibliothèque PDF (pdf-lib, PDF.js ou qpdf/mupdf compilé en WASM) pour analyser et modifier le PDF. C'est le travail lourd et il s'exécute hors du thread principal pour que l'UI ne se fige pas.
  6. Retour du résultat. Le worker produit un nouvel ArrayBuffer (ou Blob) et le renvoie au thread principal, à nouveau comme transferable.
  7. Offre en téléchargement. Le thread principal enveloppe le résultat dans un Blob, appelle URL.createObjectURL(blob) et l'offre en téléchargement via un élément <a download>. L'URL de l'objet est révoquée après le début du téléchargement pour éviter une fuite de mémoire.

À aucun moment dans ce flux le fichier ne quitte l'appareil. Il n'y a pas de fetch, pas deXMLHttpRequest, pas desendBeacon avec le contenu du fichier. Les seules requêtes réseau que la page effectue sont pour les actifs statiques (HTML, JS, CSS, polices) au premier chargement de la page.

Briques de construction

Les APIs navigateur et bibliothèques impliquées

Un outil PDF côté client s'appuie sur un petit ensemble d'APIs navigateur et un petit ensemble de bibliothèques JavaScript. Chacune fait un travail.

  • File API — les interfaces File et Blob. file.arrayBuffer() lit les octets en mémoire ; new Blob([bytes], { type: 'application/pdf' }) empaquète les octets pour le téléchargement.
  • Web Workers — un thread d'arrière-plan avec son propre heap, sans accès au DOM. L'analyse PDF s'exécute ici pour que le thread principal reste réactif. La communication se fait via postMessage ; les ArrayBuffer peuvent être transférés (déplacés, non copiés) via le second argument.
  • URL.createObjectURL / URL.revokeObjectURL — produit une URL blob: temporaire qui pointe vers le résultat en mémoire, pour qu'un élément <a download> puisse l'offrir en téléchargement. L'URL doit être révoquée sinon elle fuit.
  • pdf-lib — une bibliothèque PDF en JavaScript pur qui peut créer, modifier et ré-enregistrer des PDF. Utilisée pour fusionner, diviser, faire pivoter, filigraner, les opérations de page et les éditions de métadonnées. Ne gère pas le chiffrement (une limite connue — voir ci-dessous).
  • PDF.js — le rendu PDF de Mozilla, utilisé pour rendre des pages sur canvas (pour la conversion PDF-vers-image) et pour analyser des PDF que pdf-lib ne peut pas lire.
  • WASM (optionnel) — pour les bibliothèques qui compilent du code natif en WASM pour s'exécuter dans le navigateur à vitesse quasi-native. qpdf et mupdf peuvent être compilés en WASM ; IXPDF utilise cette voie sélectivement pour les opérations que pdf-lib ne peut pas faire.
  • CompressionStream — l'API native du navigateur pour la compression en flux (gzip, deflate). Utile pour certains chemins de réduction de taille sans livrer une bibliothèque JS de compression.

Pourquoi un worker

Pourquoi l'analyse PDF ne s'exécute pas sur le thread principal

L'analyse PDF est gourmande en CPU et de forme synchrone — on lit les octets, on décode les objets, on suit les références croisées, on construit un arbre en mémoire. Un PDF de 50 Mo peut prendre des centaines de millisecondes à analyser, et un PDF de 200 Mo peut prendre des secondes. Si ce travail s'exécute sur le thread principal, la page est figée pendant toute la durée : ni animation, ni défilement, ni saisie. Le navigateur peut afficher un dialogue « la page ne répond pas ».

Déplacer le travail vers un Web Worker résout cela. Le thread principal reste réactif ; le worker traite le PDF en arrière-plan ; la page affiche un indicateur de progression et met à jour l'UI quand le worker renvoie un résultat. La contrepartie est que le worker n'a pas accès au DOM, donc tout travail d'UI doit se faire sur le thread principal après le retour du résultat.

Les workers ont aussi leur propre budget de mémoire. Un grand PDF transféré à un worker vit dans le heap du worker, pas dans celui de la page. Cela compte pour les très gros fichiers : la page peut rester légère tandis que le worker détient le buffer lourd, et le buffer est libéré quand le worker a fini.

Objets transferable

Déplacer les octets, pas les copier

Quand un ArrayBuffer est envoyé à un worker sans transfert, les octets sont copiés — le worker obtient sa propre copie, et le thread principal conserve l'original. Pour un PDF de 100 Mo, cela signifie 200 Mo de mémoire utilisée et un temps de copie perceptible.

La solution est la liste de transfert : le second argument de postMessage. Lister le buffer dans la liste de transfert déplace les octets vers le worker — la référence du thread principal est détachée (longueur nulle), et le worker prend possession. Pas de copie, pas de mémoire doublée. Le même truc est utilisé pour renvoyer le résultat.

C'est un petit détail qui compte beaucoup à l'échelle. Sans les transferables, le traitement PDF côté client de gros fichiers serait impraticable.

Limites honnêtes

Ce qu'un navigateur ne peut pas faire bien

Le traitement côté client n'est pas une balle d'argent. Certaines opérations sont difficiles ou impossibles à faire bien dans un navigateur aujourd'hui, et un outil honnête le dit plutôt que de les falsifier.

  • OCR. La reconnaissance optique de caractères sur des PDF numérisés nécessite un modèle entraîné et beaucoup de CPU. L'OCR en navigateur existe (Tesseract.js) mais la qualité est bien en deçà du Tesseract desktop ou de l'OCR cloud. IXPDF marque l'OCR comme Research Required.
  • Chiffrement PDF (protection par mot de passe). pdf-lib ne gère pas encore l'écriture de PDF chiffrés. L'ajouter nécessite une autre bibliothèque ou qpdf compilé en WASM. L'outil Protect PDF d'IXPDF est Research Required.
  • PDF vers Word/Excel/PowerPoint. Convertir un PDF en fichier Office éditable est un problème de reconstruction de mise en page qui nécessite un backend. Les bibliothèques de navigateur qui le tentent produisent une sortie de faible fidélité. IXPDF n'offre pas ces conversions.
  • Résumé IA / Questions-réponses. Nécessite un modèle et un backend. Ne peut pas être fait côté client avec une qualité acceptable en 2026. IXPDF n'offre pas de fonctionnalités IA.
  • Très gros fichiers. Un onglet de navigateur a un budget de mémoire (généralement quelques Go). Un PDF de 2 Go fera un OOM dans la plupart des navigateurs. Les outils côté serveur gèrent cela avec le streaming ; les outils de navigateur ne peuvent pas streamer un PDF de la même manière.

La démarche honnête est de marquer ces fonctionnalités comme Planned, Research Required ouFuture Backend Candidate dans l'UI, et ne pas livrer un faux outil qui renvoie une sortie vide et prétend avoir réussi. C'est la ligne entre un outil local-first et une page « tool » de content-farm.

Pourquoi ça compte

La propriété de confidentialité est structurelle, pas une promesse

La raison pour laquelle le traitement côté client est une propriété de confidentialité significative — pas juste une affirmation marketing — est que la garantie de non téléversement est imposée par la structure du code, pas par une politique. Il n'y a pas de serveur vers lequel téléverser. La page n'a pas d'appelfetch qui transporte le contenu du fichier. Un utilisateur peut ouvrir DevTools, aller dans l'onglet Network, exécuter une opération et vérifier qu'aucune requête ne transporte le fichier. La garantie est auditable.

Cela diffère d'un outil côté serveur qui prometde supprimer votre fichier après 24 heures. Cette promesse est imposée par la politique et une infrastructure que vous ne pouvez pas voir. Le traitement côté client est imposé par l'absence de serveur. Pour les fichiers sensibles, c'est la différence qui compte.

En savoir plus dans la page de confidentialité d'IXPDF et à propos d'IXPDF.

À lire ensuite

Ressources associées