Un contrat numérisé représente quelques centaines de points par pouce d'encre noire sur papier blanc. Stocké sous forme de bitmap avec un bit par pixel, il est déjà petit, pourtant une centaine de telles pages gonflent encore un PDF au-delà de ce que vous pourriez envoyer par e-mail. Le bon filtre change l'arithmétique. JBIG2 offre le taux de compression le plus élevé défini par la norme ISO 32000-1 pour les images binaires, et sur une pile de texte numérisé, il réduit couramment de moitié ce que produit le CCITT Group 4. C'est le filtre à utiliser lorsque l'entrée est télécopiée, numérisée ou autrement réduite à deux couleurs, et HotPDF peut l'écrire directement dans un PDF
Le format atteint ce ratio grâce à deux idées qu'un codec d'image générique ne possède pas. Il modélise la façon dont les traits noirs se détachent sur un fond blanc, et il note qu'une page numérisée est principalement composée des quelques mêmes centaines de formes de glyphes répétées des milliers de fois. Comprendre ces deux éléments est ce qui vous permet de choisir délibérément les options d'encodage au lieu de deviner
Où se situe JBIG2 dans la spécification PDF
La norme ISO 32000-1 répertorie JBIG2Decode parmi les filtres de flux dans la section 7.4.7, disponibles à partir du PDF 1.4. Il s'applique à un seul endroit : les XObjects d'image dont le /BitsPerComponent est 1 et dont l'espace colorimétrique se résout en un seul canal. C'est là tout l'intérêt. JBIG2 est un codec binaire, il ne concurrence donc jamais DCT ou JPXDecode sur les photographies. Il concurrence CCITTFaxDecode, les filtres de télécopie du groupe 3 et du groupe 4, exactement sur le type de page bicolore que produit un scanner de documents
Le décodeur consomme l'organisation JBIG2 intégrée que la norme appelle le profil PDF, où chaque flux d'image contient une séquence de segments plutôt qu'un simple flux binaire. Un flux /JBIG2Globals optionnel transporte les segments partagés entre plusieurs images du même document, ce qui est le mécanisme qui permet au contenu répété d'être stocké une seule fois pour un fichier entier plutôt qu'une fois par page. HotPDF émet le flux par image par défaut et garde le canal global libre à moins qu'un back-end ne le demande
L'architecture de l'encodeur axée sur le back-end
Un encodeur JBIG2 complet est un logiciel volumineux, et ses parties les plus agressives ont historiquement été encombrées par des brevets et distribuées sous des licences qui ne conviennent pas à chaque produit. HotPDF résout cette tension en séparant l'interface du moteur. L'unité HPDFJBIG2 définit les appels que le reste de la bibliothèque effectue, et elle est livrée avec un modeste encodeur intégré afin que JBIG2 fonctionne directement. Lorsque vous avez besoin de ratios de qualité production, vous enregistrez un moteur plus puissant et la bibliothèque lui délègue la tâche, sans aucun changement dans votre code d'appel
Le basculement se fait par un seul appel d'enregistrement. Sans back-end enregistré, l'encodeur se rabat sur son chemin intégré. Enregistrez-en un et chaque encodage ultérieur passera par celui-ci
uses
HPDFJBIG2;
// Query what is active, then optionally install a stronger engine.
if not IsJBIG2EncoderBackendAvailable then
// Production backend not present: HotPDF uses its built-in MMR path.
RegisterJBIG2EncoderBackend(MyVendorJBIG2Encode);
// Later, to return to the built-in behaviour:
// ClearJBIG2Backends;
Le même crochet existe pour le décodage via RegisterJBIG2DecoderBackend, avec IsJBIG2DecoderBackendAvailable pour le sonder. C'est pourquoi une bibliothèque est livrée avec un petit chemin intégré plus une interface de back-end plutôt qu'un seul encodeur monolithique. Le chemin intégré garde le binaire léger et libre de toute complication de licence, tandis que l'interface permet à une équipe qui a souscrit une licence pour un encodeur complet de le brancher sans toucher du tout à la couche d'écriture PDF
Ce que les options d'encodage échangent réellement
L'encodage est configuré via TJBIG2EncodeOptions, un enregistrement avec les champs Lossless, UseGlobalSegments, UseSymbolDictionary et LossyLevel. L'enveloppe compatible avec les composants THPDFJBIG2Options publie Lossless, UseSymbolDictionary et LossyLevel afin qu'ils puissent être définis depuis l'Object Inspector, et elle les convertit en enregistrement en interne. Trois intentions guident les paramètres
La reconstruction sans perte conserve chaque pixel. Définissez Lossless sur True et laissez LossyLevel à zéro, et le bitmap décodé est identique bit pour bit à l'entrée. C'est le seul choix sûr pour les dessins au trait, les dessins techniques et toute page où un pixel supprimé pourrait changer la signification, comme une signature ou un tampon. Le codage par dictionnaire de symboles active la déduplication sensible au texte et est l'option qui sépare JBIG2 des filtres de télécopie. Le niveau de perte, un entier de 0 à 9, permet à un back-end performant d'échanger la fidélité contre la taille en traitant des marques presque identiques comme le même symbole. Zéro signifie sans perte. L'encodeur intégré n'honore que le chemin sans perte et ignore tout niveau de perte non nul, de sorte que les niveaux supérieurs ne prennent effet qu'une fois qu'un back-end qui les implémente est enregistré
var
Options: TJBIG2EncodeOptions;
begin
Options := DefaultJBIG2EncodeOptions; // Lossless True, symbol dictionary on
Options.Lossless := True;
Options.LossyLevel := 0; // 0 keeps every pixel
Options.UseSymbolDictionary := True; // dedupe repeated glyphs
// Pass Options to a backend, or let THPDFJBIG2Options carry them.
end;
Les dictionnaires de symboles et pourquoi les numérisations de texte l'emportent
Une page de texte numérisé n'est pas vraiment une image de mots. C'est la même lettre e imprimée plusieurs centaines de fois, le même t, la même virgule, chaque occurrence étant une copie légèrement bruitée d'une forme sous-jacente. Un dictionnaire de symboles capture cette structure. L'encodeur rassemble les marques distinctes de la page dans un dictionnaire, stocke chaque forme une fois, puis enregistre la page sous la forme d'une liste de positions qui font référence aux entrées du dictionnaire. Mille occurrences du même glyphe coûtent un bitmap stocké plus mille placements peu coûteux
C'est précisément là que JBIG2 prend l'avantage sur le CCITT Group 4. Le Group 4 code chaque ligne de balayage par rapport à la ligne située au-dessus sans notion de glyphe, il paie donc le coût total de chaque lettre à chaque fois que la lettre apparaît. JBIG2 paie une seule fois. Lorsque le même dictionnaire est promu vers le flux global au niveau du document, l'économie se cumule sur une numérisation de plusieurs pages, car les formes partagées par page après page sont stockées une seule fois pour l'ensemble du fichier. Sur du texte dense, la différence n'est pas marginale. C'est la raison pour laquelle JBIG2 existe
Région générique et MMR pour tout le reste
Toute image binaire n'est pas du texte. Les cartes, les schémas, les dessins d'ingénierie et les pages mixtes comportent des dessins au trait qu'aucun dictionnaire ne peut résumer. Pour ceux-ci, JBIG2 code une région générique, un rectangle de pixels compressés directement sans aucune formation de symboles. La norme permet à une région générique d'utiliser MMR, le codage READ modifié modifié que la télécopie Group 4 utilise déjà, qui modélise chaque ligne de pixels par rapport à la ligne au-dessus
C'est le chemin que HotPDF livre dans son encodeur intégré. Lorsqu'aucun back-end n'est enregistré et que la requête est sans perte, la bibliothèque compresse le bitmap comme une seule région générique MMR et l'enveloppe dans la structure de segment JBIG2 requise par le profil PDF. Il ne nécessite aucun dictionnaire, aucune passe d'apprentissage et aucune seconde image pour référence, c'est donc la valeur par défaut fiable pour les dessins au trait et le contenu binaire mixte. Il n'égalera pas un encodeur de dictionnaire de symboles complet sur du texte pur, mais il est toujours correct, toujours sans perte et toujours présent. La surface de l'encodeur pour cela est un seul appel
var
Encoder: THPDFJBIG2Encoder;
ImageData: TJBIG2ByteArray;
Scanlines: TJBIG2ScanlineArray; // one byte array per row, MSB-first
W, H: Integer;
begin
// Scanlines, W and H describe a 1-bit page; each row is (W + 7) div 8 bytes.
Encoder := THPDFJBIG2Encoder.Create;
try
if Encoder.EncodeToByteArray(Scanlines, W, H, ImageData) then
// ImageData now holds a JBIG2 stream ready for a /JBIG2Decode XObject.
;
finally
Encoder.Free;
end;
end;
L'activer lors de la construction d'un document
Pour une utilisation quotidienne, vous ne touchez pas directement à la classe d'encodeur. HotPDF expose JBIG2 comme un choix de compression d'image sur le document. L'énumération THPDFImageCompressionType inclut icJBIG2 aux côtés des options Flate, JPEG et CCITT, et le document possède une propriété JBIG2Options de type THPDFJBIG2Options qui contient les paramètres utilisés lorsque cette compression est sélectionnée. Configurez les deux avant d'ajouter les images binaires que vous souhaitez compresser de cette manière
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.ImageCompressionType := icJBIG2; // route 1-bit images through JBIG2
Pdf.JBIG2Options.Lossless := True; // keep every pixel
Pdf.JBIG2Options.UseSymbolDictionary := True;
Pdf.JBIG2Options.LossyLevel := 0;
// Add pages and place your scanned 1-bit images here.
finally
Pdf.Free;
end;
end;
Une commodité à noter est l'add-on DBGridHotPDFExport, qui rend un TDBGrid directement dans un PDF. Sa sortie est en grande partie constituée de règles binaires et de texte, de sorte qu'un document configuré pour JBIG2 garde ces exportations compactes sans aucune manipulation supplémentaire de votre part. Deux sujets connexes sur ce blog approfondissent le flux de travail environnant. Pour savoir comment les images et les polices sont disposées lorsque vous construisez des rapports, consultez la section sortie de rapport avec polices et images dans Delphi. Lorsqu'un document compressé doit satisfaire un profil d'archivage, les règles de validation PDF/A, PDF/X et PDF/UA dans Delphi vous indiquent quels filtres un niveau de conformité donné accepte. JBIG2 est livré dans le cadre du HotPDF Component pour Delphi et C++Builder, à côté des API de chargement, d'édition et de chiffrement couvertes par ailleurs ici