Ένα σαρωμένο συμβόλαιο είναι μερικές εκατοντάδες κουκκίδες ανά ίντσα μαύρης μελάνης σε λευκό χαρτί. Αποθηκευμένο ως bitmap ενός bit ανά pixel είναι ήδη μικρό, όμως εκατό τέτοιες σελίδες ακόμα φουσκώνουν ένα PDF πέρα από οτιδήποτε θα στέλνατε μέσω email. Το σωστό φίλτρο αλλάζει την αριθμητική. Το JBIG2 είναι η συμπίεση με τον υψηλότερο λόγο που ορίζει το ISO 32000-1 για δικατάστατες εικόνες, και σε μια στοίβα σαρωμένου κειμένου συνήθως υποδιπλασιάζει ό,τι παράγει το CCITT Group 4. Αυτό είναι το φίλτρο για fax, σαρωμένο ή αλλιώς μειωμένο σε δύο χρώματα υλικό, και το HotPDF μπορεί να το γράψει απευθείας σε ένα PDF
Ο μορφότυπος κερδίζει το λόγο με δύο ιδέες που ένας γενικός codec εικόνας δεν έχει. Μοντελοποιεί πώς οι μαύρες σειρές κάθονται πάνω σε λευκό φόντο και παρατηρεί ότι μια σαρωμένη σελίδα είναι κατά κύριο λόγο οι ίδιες λίγες εκατοντάδες μορφές γλυφών που επαναλαμβάνονται χιλιάδες φορές. Κατανοώντας και τα δύο μπορείτε να επιλέξετε τις ρυθμίσεις κωδικοποίησης σκόπιμα αντί να μαντεύετε
Πού εντάσσεται το JBIG2 στην προδιαγραφή PDF
Το ISO 32000-1 αναφέρει το JBIG2Decode μεταξύ των φίλτρων ροής στην §7.4.7, διαθέσιμο από το PDF 1.4 και μετά. Εφαρμόζεται μόνο σε ένα σημείο: σε image XObjects με /BitsPerComponent ίσο με 1 και χώρο χρώματος που αναλύεται σε ένα κανάλι. Αυτός είναι ο λόγος ύπαρξής του. Το JBIG2 είναι κωδικοποιητής δικατάστατης εικόνας, οπότε δεν ανταγωνίζεται ποτέ το DCT ή το JPXDecode σε φωτογραφίες. Ανταγωνίζεται το CCITTFaxDecode, τα φίλτρα fax Group 3 και Group 4, ακριβώς στο είδος της δίχρωμης σελίδας που παράγει ένας σαρωτής εγγράφων
Ο αποκωδικοποιητής χρησιμοποιεί την ενσωματωμένη οργάνωση JBIG2 που το πρότυπο αποκαλεί προφίλ PDF, όπου κάθε ροή εικόνας περιέχει μια ακολουθία τμημάτων και όχι ένα ακατέργαστο bitstream. Μια προαιρετική ροή /JBIG2Globals μεταφέρει τμήματα κοινά για πολλές εικόνες στο ίδιο έγγραφο, που είναι ο μηχανισμός που επιτρέπει στο επαναλαμβανόμενο περιεχόμενο να αποθηκεύεται μία φορά για ολόκληρο το αρχείο αντί για κάθε σελίδα. Το HotPDF εκπέμπει ανά προεπιλογή τη ροή ανά εικόνα και διατηρεί ελεύθερο το κανάλι globals εκτός αν το ζητήσει κάποιο backend
Η αρχιτεκτονική κωδικοποιητή με πρώτο το backend
Ένας πλήρης κωδικοποιητής JBIG2 είναι ένα μεγάλο κομμάτι λογισμικού, και τα πιο επιθετικά μέρη του είναι ιστορικά φορτωμένα με διπλώματα ευρεσιτεχνίας και αποστέλλονται με άδειες που δεν ταιριάζουν σε κάθε προϊόν. Το HotPDF επιλύει αυτή την ένταση διαχωρίζοντας τη διεπαφή από τη μηχανή. Η μονάδα HPDFJBIG2 ορίζει τις κλήσεις που κάνει η υπόλοιπη βιβλιοθήκη και αποστέλλεται με έναν σεμνό ενσωματωμένο κωδικοποιητή ώστε το JBIG2 να λειτουργεί αμέσως. Όταν χρειάζεστε λόγους επαγγελματικής κλάσης καταχωρείτε μια ισχυρότερη μηχανή και η βιβλιοθήκη αναθέτει σε αυτήν, χωρίς καμία αλλαγή στον κώδικα κλήσής σας
Η αλλαγή είναι μια μοναδική κλήση καταχώρισης. Χωρίς καταχωρισμένο backend ο κωδικοποιητής επιστρέφει στη διαδρομή του ενσωματωμένου. Καταχωρίστε ένα και κάθε επόμενη κωδικοποίηση εκτελείται μέσω αυτού
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;
Το ίδιο hook υπάρχει για αποκωδικοποίηση μέσω του RegisterJBIG2DecoderBackend, με το IsJBIG2DecoderBackendAvailable για διερεύνηση. Γι' αυτό μια βιβλιοθήκη αποστέλλεται με μια μικρή ενσωματωμένη διαδρομή και μια ραφή backend αντί για έναν μονολιθικό κωδικοποιητή. Η ενσωματωμένη διαδρομή κρατά το δυαδικό αδύνατο και απαλλαγμένο από δεσμεύσεις αδειών, ενώ η ραφή επιτρέπει σε μια ομάδα που έχει αδειοδοτήσει έναν πλήρη κωδικοποιητή να τον συνδέσει χωρίς να αγγίξει καθόλου το επίπεδο εγγραφής PDF
Τι αντισταθμίζουν οι επιλογές κωδικοποίησης
Η κωδικοποίηση ρυθμίζεται μέσω του TJBIG2EncodeOptions, μιας εγγραφής με τα πεδία Lossless, UseGlobalSegments, UseSymbolDictionary και LossyLevel. Ο φιλικός προς τα component wrapper THPDFJBIG2Options δημοσιεύει τα Lossless, UseSymbolDictionary και LossyLevel ώστε να ρυθμίζονται από το Object Inspector, και μετατρέπει εσωτερικά στην εγγραφή. Τρεις προθέσεις καθοδηγούν τις ρυθμίσεις
Η αδιάρρηκτη ανακατασκευή διατηρεί κάθε pixel. Ρυθμίστε το Lossless σε True και αφήστε το LossyLevel στο μηδέν, και το αποκωδικοποιημένο bitmap είναι bit-για-bit πανομοιότυπο με την είσοδο. Αυτή είναι η μόνη ασφαλής επιλογή για line art, τεχνικά σχέδια και κάθε σελίδα όπου ένα χαμένο pixel μπορεί να αλλάξει νόημα, όπως υπογραφή ή σφραγίδα. Η κωδικοποίηση λεξικού συμβόλων ενεργοποιεί την αντιγραφή με επίγνωση κειμένου και είναι η επιλογή που διαχωρίζει το JBIG2 από τα φίλτρα fax. Το επίπεδο απωλειών, ακέραιος από 0 έως 9, επιτρέπει σε ικανό backend να αντισταθμίσει πιστότητα με μέγεθος αντιμετωπίζοντας σχεδόν πανομοιότυπα σήματα ως το ίδιο σύμβολο. Το μηδέν σημαίνει χωρίς απώλειες. Ο ενσωματωμένος κωδικοποιητής τιμά μόνο τη διαδρομή χωρίς απώλειες και αγνοεί οποιοδήποτε μη μηδενικό επίπεδο απωλειών, οπότε τα υψηλότερα επίπεδα ισχύουν μόνο αφού καταχωρηθεί backend που τα υλοποιεί
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;
Λεξικά συμβόλων και γιατί οι σαρώσεις κειμένου κερδίζουν
Μια σελίδα σαρωμένου κειμένου δεν είναι πραγματικά μια εικόνα λέξεων. Είναι το ίδιο γράμμα e τυπωμένο αρκετές εκατοντάδες φορές, το ίδιο t, το ίδιο κόμμα, κάθε παράδειγμα ένα ελαφρώς θορυβώδες αντίγραφο ενός υποκείμενου σχήματος. Ένα λεξικό συμβόλων συλλαμβάνει αυτή τη δομή. Ο κωδικοποιητής συλλέγει τα διακριτά σήματα της σελίδας σε ένα λεξικό, αποθηκεύει κάθε σχήμα μία φορά και στη συνέχεια καταγράφει τη σελίδα ως λίστα θέσεων που αναφέρονται σε καταχωρίσεις λεξικού. Χίλιες εμφανίσεις του ίδιου γλυφού κοστίζουν ένα αποθηκευμένο bitmap συν χίλιες φθηνές τοποθετήσεις
Εδώ ακριβώς το JBIG2 ξεπερνά το CCITT Group 4. Το Group 4 κωδικοποιεί κάθε γραμμή σάρωσης σε σχέση με την παραπάνω χωρίς έννοια γλυφού, οπότε πληρώνει το πλήρες κόστος κάθε γράμματος κάθε φορά που εμφανίζεται. Το JBIG2 πληρώνει μία φορά. Όταν το ίδιο λεξικό προβιβαστεί στη ροή globals επιπέδου εγγράφου, η εξοικονόμηση πολλαπλασιάζεται σε μια πολυσέλιδη σάρωση, καθώς τα σχήματα που μοιράζονται σελίδα μετά σελίδα αποθηκεύονται μία μόνο φορά για ολόκληρο το αρχείο. Σε πυκνό κείμενο η διαφορά δεν είναι οριακή. Είναι ο λόγος ύπαρξης του JBIG2
Γενική περιοχή και MMR για όλα τα άλλα
Δεν είναι κάθε δικατάστατη εικόνα κείμενο. Χάρτες, σχηματικά διαγράμματα, τεχνικά σχέδια και μικτές σελίδες έχουν line art που κανένα λεξικό δεν μπορεί να συνοψίσει. Γι' αυτά το JBIG2 κωδικοποιεί μια γενική περιοχή, ένα ορθογώνιο pixel συμπιεσμένο απευθείας χωρίς εκπαίδευση συμβόλων. Το πρότυπο επιτρέπει σε γενική περιοχή να χρησιμοποιεί MMR, την κωδικοποίηση modified modified READ που χρησιμοποιεί ήδη το fax Group 4 και που μοντελοποιεί κάθε σειρά pixel σε σχέση με την παραπάνω
Αυτή είναι η διαδρομή που αποστέλλεται στον ενσωματωμένο κωδικοποιητή του HotPDF. Όταν δεν είναι καταχωρισμένο backend και το αίτημα είναι χωρίς απώλειες, η βιβλιοθήκη συμπιέζει το bitmap ως μια ενιαία MMR γενική περιοχή και τη τυλίγει στη δομή τμημάτων JBIG2 που απαιτεί το προφίλ PDF. Δεν χρειάζεται λεξικό, πέρασμα εκπαίδευσης ή δεύτερη εικόνα αναφοράς, οπότε είναι η αξιόπιστη προεπιλογή για line art και μικτό δικατάστατο περιεχόμενο. Δεν θα ταιριάξει με έναν πλήρη κωδικοποιητή λεξικού συμβόλων σε καθαρό κείμενο, αλλά είναι πάντα σωστός, πάντα χωρίς απώλειες και πάντα παρών. Η επιφάνεια κωδικοποιητή για αυτόν είναι μία κλήση
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;
Ενεργοποίηση κατά τη δημιουργία εγγράφου
Για καθημερινή χρήση δεν αγγίζετε απευθείας την κλάση κωδικοποιητή. Το HotPDF εκθέτει το JBIG2 ως επιλογή συμπίεσης εικόνας στο έγγραφο. Η απαρίθμηση THPDFImageCompressionType περιλαμβάνει το icJBIG2 δίπλα στις επιλογές Flate, JPEG και CCITT, και το έγγραφο φέρει ιδιότητα JBIG2Options τύπου THPDFJBIG2Options που περιέχει τις ρυθμίσεις που χρησιμοποιούνται όταν επιλέγεται αυτή η συμπίεση. Ρυθμίστε και τα δύο πριν προσθέσετε τις δικατάστατες εικόνες που θέλετε να συμπιέσετε με αυτόν τον τρόπο
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;
Αξίζει να σημειωθεί η προσθήκη DBGridHotPDFExport, που αποδίδει ένα TDBGrid απευθείας σε PDF. Η έξοδός του είναι σε μεγάλο βαθμό δικατάστατοι κανόνες και κείμενο, οπότε ένα έγγραφο ρυθμισμένο για JBIG2 διατηρεί αυτές τις εξαγωγές συμπαγείς χωρίς επιπλέον χειρισμό από μέρους σας. Δύο σχετικά θέματα σε αυτό το ιστολόγιο εμβαθύνουν στην περιβάλλουσα ροή εργασίας. Για το πώς τοποθετούνται εικόνες και γραμματοσειρές κατά τη δημιουργία αναφορών, δείτε εξαγωγή αναφορών με γραμματοσειρές και εικόνες στη Delphi. Όταν ένα συμπιεσμένο έγγραφο πρέπει να πληροί ένα αρχειακό προφίλ, οι κανόνες στο επικύρωση PDF/A, PDF/X και PDF/UA στη Delphi σας λένε ποια φίλτρα αποδέχεται ένα δεδομένο επίπεδο συμμόρφωσης. Το JBIG2 αποστέλλεται ως μέρος του HotPDF Component για Delphi και C++Builder, δίπλα στα API φόρτωσης, επεξεργασίας και κρυπτογράφησης που καλύπτονται αλλού εδώ