Créer un code‑barres PDF417 ne nécessite que quatre lignes de Python. Lire ce code à partir d’une photo prise avec un téléphone, d’un scan à 200 DPI ou d’une carte d’embarquement qui a passé une journée dans la poche de quelqu’un est le moment où le vrai travail commence, et c’est là que la plupart des intégrations PDF417 échouent réellement. Dans cet article, vous apprendrez comment lire les codes‑barres PDF417 en Python lorsque l’image source est imparfaite. Si vous cherchez plutôt la partie génération, le guide précédent sur la façon de générer des codes‑barres PDF417 avec Python couvre la création de symboles PDF417 de base et personnalisés, y compris le contrôle des lignes et des colonnes, et le guide du lecteur de codes‑barres Python couvre la numérisation à usage général à travers les différentes symbologies. Ce qui suit ici se concentre de manière étroite et approfondie sur la reconnaissance PDF417.

Chaque extrait ci‑dessous a été exécuté avec Aspose.BarCode for Python via .NET 26.7 sous Linux avec Python 3.12. Les temps d’exécution et les résultats de lecture/échec sont mesurés, pas estimés, et le script qui les a générés se trouve à la fin afin que vous puissiez le réexécuter sur vos propres images.

Ce qui perturbe réellement la reconnaissance PDF417

PDF417 est une symbologie empilée : des lignes de mots‑code, chaque mot‑code étant construit à partir de quatre barres et quatre espaces s’étendant sur 17 modules. Cette structure intègre la correction d’erreurs Reed‑Solomon, de sorte qu’un coin déchiré ou une tache de café est généralement survivable. Ce qui n’est pas survivable, c’est la perte de la grille de modules elle‑même.

Trois choses détruisent la grille, dans l’ordre approximatif de leur fréquence d’apparition en production :

  • Largeur de module efficace inférieure à deux pixels. C’est la défaillance dominante. Elle se produit lors de la réduction d’échelle, à cause de la distance de la caméra, ou à cause du flou, qui étale l’encre d’un module sur ses voisins. Un code‑barres généré à trois pixels par module puis flouté équivaut fonctionnellement à un code‑barres à un pixel par module.
  • Perspective et rotation. Un code‑barres photographié sous un angle a des rangées qui ne sont plus parallèles aux lignes de balayage. Le détecteur gère cela, mais cela nécessite un passage de détection que le préréglage le plus rapide ignore.
  • Effondrement du contraste. Papier thermique qui a pâli, écran photographié sous l’éblouissement, ou numérisation avec la luminosité figée. Moins fatal qu’il n’y paraît, comme le montrent les chiffres ci‑dessous.

La conséquence pratique est que les paramètres de reconnaissance sont un mécanisme de récupération, et non un substitut à la qualité de capture. Ils vous permettent de récupérer la bande moyenne de la qualité d’image. Ils ne permettent pas de récupérer la partie inférieure.

Configurer le lecteur PDF417 en Python

Installez la bibliothèque depuis PyPI :

pip install aspose-barcode-for-python-via-net

L’API de reconnaissance se trouve dans aspose.barcode.barcoderecognition. Deux classes sont importantes pour cet article : BarCodeReader, qui gère la détection et le décodage, et QualitySettings, qui contrôle l’intensité avec laquelle le lecteur travaille.

Lire un code-barres PDF417 en Python

La lecture minimale viable nécessite deux arguments et une boucle :

from aspose.barcode import barcoderecognition as rec

reader = rec.BarCodeReader("clean.png", rec.DecodeType.PDF417)

for result in reader.read_bar_codes():
    print("Code text:", result.code_text)
    print("Symbology:", result.code_type_name)
    print("Reading quality:", result.reading_quality)
Lire un code-barres PDF417 en Python.

Lire un code-barres PDF417 en Python.

Résultat sur une image propre :

Code text: PASSENGER|KHAN/M|SEAT14C|LHE-DXB
Symbology: Pdf417
Reading quality: 100.0

Le deuxième argument n’est pas optionnel en pratique. Omettez‑le et BarCodeReader revient à DecodeType.ALL_SUPPORTED_TYPES, ce qui lance la détection de plus de soixante symbologies sur chaque région candidate de l’image. Sur un pipeline uniquement PDF417, c’est du pur gaspillage, et cela ouvre la porte à un faux positif de symbologie linéaire à l’intérieur de la structure de ligne PDF417. Nommez le type.

Si votre entrée arrive sous forme d’octets provenant d’un téléchargement plutôt que d’un fichier sur le disque, transmettez un flux et définissez un délai d’attente afin qu’une image pathologique ne puisse pas bloquer un travailleur :

import io
from aspose.barcode import barcoderecognition as rec

def decode_pdf417(image_bytes, timeout_ms=2000):
    reader = rec.BarCodeReader(io.BytesIO(image_bytes), rec.DecodeType.PDF417)
    reader.timeout = timeout_ms
    return [r.code_text for r in reader.read_bar_codes()]

Comparer les paramètres de qualité de reconnaissance PDF417 en Python

QualitySettings propose quatre préréglages à connaître. L’assigner au lecteur se fait en une seule ligne :

reader = rec.BarCodeReader("scan.png", rec.DecodeType.PDF417)
reader.quality_settings = rec.QualitySettings.high_quality
PresetDestiné àCoût
high_performanceImages propres, générées par machineLe plus rapide, saute les passes de récupération
normal_qualityPar défaut. Scans et exportations réguliersÉquilibré
high_qualityCaptures d’appareil photo, scans dégradésModéré
max_qualityPasse de réessai sur les images déjà échouéesLe plus lent de loin

Pour savoir ce que ces descriptions signifient en pratique, j’ai généré un PDF417 à trois pixels par module, l’ai dégradé de six manières avec Pillow, et j’ai exécuté chaque préréglage contre chaque variante. Médiane de trois exécutions :

Image sourcehigh_performancenormal_qualityhigh_qualitymax_quality
Proprelu, 35 mslu, 50 mslu, 45 mslu, 106 ms
Pivoté de 12°, floumanqué, 15 mslu, 74 mslu, 67 mslu, 157 ms
Bruit gaussien (σ 40)lu, 31 mslu, 49 mslu, 52 mslu, 123 ms
Demi résolutionlu, 22 mslu, 37 mslu, 35 mslu, 86 ms
Faible contrastelu, 24 mslu, 38 mslu, 43 mslu, 112 ms
Flou important (σ 2.2)manqué, 5 msmanqué, 25 msmanqué, 85 msmanqué, 180 ms

Quatre choses ressortent de ce tableau, et elles sont plus utiles que les chiffres individuels :

  1. Le bruit et le faible contraste ne sont pas le problème que les gens croient. Reed-Solomon plus le détecteur ont absorbé un bruit gaussien important et une réduction de contraste de 82 % sur le préréglage le plus rapide. Arrêtez d’ajuster pour ceux‑ci.
  2. La rotation plus le flou est le cas qui sépare les préréglages. C’est également le profil exact d’une capture à partir d’un téléphone portable, ce qui explique pourquoi high_performance est le mauvais défaut pour tout pipeline provenant d’un mobile.
  3. max_quality coûte trois fois le temps de normal_quality et ne lit rien de supplémentaire. Il mérite sa place comme voie de seconde tentative, pas comme défaut.
  4. Une fois la grille du module disparue, aucun préréglage ne la récupère. La ligne de flou important est un échec généralisé, et max_quality a passé 180 ms à le prouver. C’est un problème de capture avec une solution de capture : plus de pixels, une meilleure mise au point, un x_dimension plus grand lors de la génération.

Ajuster QualitySettings pour lire les codes-barres PDF417 flous en Python

Un préréglage est un ensemble de propriétés individuelles, et vous pouvez partir d’un préréglage et en remplacer une. C’est là que résident les véritables gains pour un défaut connu et reproductible.

L’image tournée et floue ci‑dessus est une bonne démonstration. Sous high_performance elle manque. Activez la déconvolution sur le même préréglage et cela donne :

from aspose.barcode import barcoderecognition as rec

reader = rec.BarCodeReader("rotated.png", rec.DecodeType.PDF417)

quality = rec.QualitySettings.high_performance
quality.deconvolution = rec.DeconvolutionMode.NORMAL
reader.quality_settings = quality

for result in reader.read_bar_codes():
    print(result.code_text)
Ajustez QualitySettings pour lire les codes-barres PDF417 flous en Python.

Ajustez QualitySettings pour lire les codes-barres PDF417 flous en Python.

Mesuré : échec en 12 ms sans le remplacement, lecture en 54 ms avec. Une propriété a inversé le résultat, et le résultat est toujours revenu plus rapidement que le préréglage max_quality ne l’aurait fait.

Les propriétés à connaître :

PropertyValuesQuand l’utiliser
deconvolutionFAST, NORMAL, SLOWFlou de mouvement et captures hors mise au point
barcode_qualityHIGH, NORMAL, LOWDéfauts d’impression, décoloration thermique, artefacts de fax
x_dimensionAUTO, SMALL, NORMAL, LARGE, USE_MINIMAL_X_DIMENSIONCodes-barres denses, ou une taille de module fixe connue
minimal_x_dimensionfloatÀ associer avec USE_MINIMAL_X_DIMENSION pour définir une valeur minimale
complex_backgroundAUTO, DISABLED, ENABLEDCode-barres imprimé sur une illustration ou un formulaire à motifs
inverse_imageAUTO, DISABLED, ENABLEDCodes-barres blanc sur noir, captures d’écran
allow_incorrect_barcodesboolDiagnostics uniquement, jamais en production

Ce dernier mérite un avertissement. allow_incorrect_barcodes renvoie des symboles qui ont échoué la validation du contrôle de somme. C’est une aide au débogage pour répondre à « did the detector even find something here? ». Le déployer signifie expédier des chaînes décodées qui sont incorrectes plutôt qu’absentes, ce qui est strictement pire qu’un simple manque.

Une stratégie de hiérarchisation qui fonctionne bien en production : essayez d’abord normal_quality, puis, en cas d’échec, réessayez une fois avec high_quality plus deconvolution = SLOW. Vous ne payez le chemin coûteux que pour les images qui en ont besoin.

Valider les résultats du décodage PDF417 en Python

Une chaîne décodée n’est pas automatiquement une chaîne correcte. Trois champs sur BarCodeResult aident :

for result in reader.read_bar_codes():
    print("Text:", result.code_text)
    print("Reading quality:", result.reading_quality)
    print("Confidence:", result.confidence)
    print("Region:", [(p.x, p.y) for p in result.region.points])
Text: PASSENGER|KHAN/M|SEAT14C|LHE-DXB
Reading quality: 100.0
Confidence: 100
Region: [(7, 6), (261, 7), (261, 276), (7, 277)]

Réassembler un Macro PDF417 réparti sur plusieurs images

Macro PDF417 divise un message logique en plusieurs symboles, ce qui apparaît dans les manifestes d’expédition et les documents multi‑pages. Les métadonnées du segment survivent au voyage aller‑retour, de sorte que le réassemblage est déterministe :

from aspose.barcode import barcoderecognition as rec

segments = {}
total = None

for path in ["page1.png", "page2.png"]:
    reader = rec.BarCodeReader(path, rec.DecodeType.MACRO_PDF417)
    for result in reader.read_bar_codes():
        meta = result.extended.pdf417
        segments[meta.macro_pdf_417_segment_id] = result.code_text
        total = meta.macro_pdf_417_segments_count
        print(f"{path}: segment {meta.macro_pdf_417_segment_id + 1} of {total}, "
              f"file id {meta.macro_pdf_417_file_id}")

if total and len(segments) == total:
    payload = "".join(segments[i] for i in sorted(segments))
    print("Reassembled:", payload)
else:
    print("Incomplete: missing segments")
Page 1.

Page 1.

Page 2.

Page 2.

Output:

Data\pdf417\page1.png: segment 1 of 2, file id 42
Data\pdf417\page2.png: segment 2 of 2, file id 42
Reassembled: SEGMENT-A-DATASEGMENT-B-DATA

Notez que macro_pdf_417_file_id est un entier, pas une chaîne, à la fois du côté de la génération et de la reconnaissance. Le même objet expose également macro_pdf_417_file_name, macro_pdf_417_sender, macro_pdf_417_addressee, macro_pdf_417_time_stamp et macro_pdf_417_checksum lorsque l’encodeur les a remplis.

Évaluer la reconnaissance PDF417 sur vos propres images

Le choix du préréglage doit être une mesure, pas une supposition. Pointez-le vers un dossier contenant des captures représentatives de votre pipeline réel et il vous indiquera quel préréglage justifie son coût :

import time, statistics, pathlib
from aspose.barcode import barcoderecognition as rec

PRESETS = ["high_performance", "normal_quality", "high_quality", "max_quality"]

def probe(path, preset, reps=3):
    times, found = [], False
    for _ in range(reps):
        reader = rec.BarCodeReader(str(path), rec.DecodeType.PDF417)
        reader.quality_settings = getattr(rec.QualitySettings, preset)
        start = time.perf_counter()
        results = list(reader.read_bar_codes())
        times.append((time.perf_counter() - start) * 1000)
        found = found or bool(results)
    return found, statistics.median(times)

for image in sorted(pathlib.Path("samples").glob("*.png")):
    row = []
    for preset in PRESETS:
        found, ms = probe(image, preset)
        row.append(f"{preset}: {'read' if found else 'miss'} {ms:.0f}ms")
    print(f"{image.name:28} " + " | ".join(row))
clean.png                    high_performance: read 32ms | normal_quality: read 48ms | high_quality: read 51ms | max_quality: read 130ms
faded_thermal.png            high_performance: read 26ms | normal_quality: read 43ms | high_quality: read 46ms | max_quality: read 144ms
half_resolution.png          high_performance: read 27ms | normal_quality: read 41ms | high_quality: read 41ms | max_quality: read 89ms
heavy_blur.png               high_performance: miss 7ms | normal_quality: miss 24ms | high_quality: miss 69ms | max_quality: miss 180ms
noisy_scan.png               high_performance: read 26ms | normal_quality: read 42ms | high_quality: read 47ms | max_quality: read 116ms
Page1.png                    high_performance: read 21ms | normal_quality: read 34ms | high_quality: read 38ms | max_quality: read 90ms
Page2.png                    high_performance: read 21ms | normal_quality: read 33ms | high_quality: read 38ms | max_quality: read 89ms
rotated.png                  high_performance: miss 16ms | normal_quality: read 43ms | high_quality: read 57ms | max_quality: read 147ms

Exécutez-le une fois contre cinquante captures réelles et le débat prédéfini se termine.

Directives pratiques

  • Restreignez DecodeType à PDF417 à moins que vous ne prévoyiez réellement des symbologies mixtes. Utilisez MACRO_PDF417, COMPACT_PDF417 ou MICRO_PDF417 lorsque vous connaissez la variante.
  • Recadrez avant de décoder. Fournir un scan complet A4 alors que le code‑barres n’en occupe que 5 % gaspille le temps de détection et augmente les faux positifs.
  • Conservez les fichiers intermédiaires sans perte. PNG ou TIFF. Le JPEG avec des réglages de faible qualité crée des artefacts qui affectent précisément les bords du code que le décodeur doit lire.
  • Hiérarchisez vos nouvelles tentatives plutôt que de vous rabattre sur le préréglage le plus lent.
  • Corrigez la génération avant d’ajuster la reconnaissance. Si vous contrôlez l’encodeur, augmenter x_dimension ne coûte rien et résout plus d’échecs que n’importe quel réglage du lecteur. L’article sur la génération PDF417 couvre ces paramètres.
  • Définissez timeout sur tout lecteur qui traite des images fournies par l’utilisateur.

Obtenez une licence gratuite

La version d’évaluation ajoute un filigrane au texte décodé pour les symbologies autres que Code 39, ce qui interférera avec tout test de bout en bout que vous effectuez. Une licence temporaire gratuite supprime cela pour l’évaluation.

Ressources supplémentaires gratuites

Conclusion

Lire les codes‑barres PDF417 en Python est une opération en deux lignes sur des images propres et un problème d’ingénierie sur les images réelles. Les mesures ci‑dessus indiquent une posture simple : nommez votre DecodeType, utilisez normal_quality par défaut, réessayez une fois avec high_quality et la déconvolution activée, puis validez chaque résultat avant d’agir. Conservez les préréglages coûteux pour le chemin de réessai et, lorsqu’une classe entière d’images échoue à chaque réglage, corrigez la capture plutôt que le lecteur. Les questions sont les bienvenues sur le forum de support gratuit.

FAQs

  1. Pourquoi le même code‑barres PDF417 est‑il lu dans une image et échoue dans une autre ?
    La reconnaissance dépend du nombre de pixels que chaque module occupe après la capture. Le flou, la réduction d’échelle et la compression JPEG réduisent tous la largeur effective du module, et lorsqu’un module descend en dessous d’environ deux pixels nets, aucun préréglage ne pourra le récupérer.

  2. Quel préréglage de reconnaissance devrais‑je utiliser pour PDF417 ?
    Commencez avec normal_quality, qui est la valeur par défaut. Passez à high_quality pour les captures et les scans avec appareil photo, et réservez max_quality pour les passes de réessai car il est plusieurs fois plus lent sans lire beaucoup plus.

  3. Restreindre DecodeType à PDF417 accélère‑t‑il réellement la lecture ?
    Oui. La valeur par défaut est DecodeType.ALL_SUPPORTED_TYPES, qui exécute le détecteur pour chaque symbologie prise en charge. Spécifier explicitement PDF417 supprime ce travail et élimine également la possibilité d’un faux positif provenant d’une autre symbologie.

  4. Aspose.BarCode peut‑il lire un message Macro PDF417 réparti sur plusieurs images ?
    Oui. Lisez chaque segment avec DecodeType.MACRO_PDF417 et utilisez macro_pdf_417_file_id, macro_pdf_417_segment_id et macro_pdf_417_segments_count sur le résultat étendu pour réassembler la charge utile dans l’ordre.

  5. Comment savoir si un résultat décodé est fiable ?
    Vérifiez reading_quality et confidence sur le BarCodeResult, et utilisez le quadrilatère region pour confirmer que le code‑barres a été trouvé à l’endroit attendu dans l’image.

  6. Peut‑il lire un PDF417 à partir d’une photo d’un permis de conduire ou d’une carte d’embarquement ?
    Oui, à condition que la capture soit nette et que le code‑barres ne soit pas coupé. Recadrez la région du code‑barres avant la lecture, et privilégiez le PNG plutôt que le JPEG pour les fichiers intermédiaires.

En savoir plus