Le PDF semble horizontal, mais les coordonnées extraites sont fausses : expliquez clairement la matrice de rotation

Analysez le problème de désalignement des coordonnées des pages PDF pivotées et expliquez en détail la conversion matricielle entre l'espace non pivoté et l'espace d'affichage dans PyMuPDF. Fournit des exemples de synthèse de mémoire et des listes de contrôle d'acceptation pour expliquer comment utiliser OmniDoc pour évaluer les effets complexes de restauration de mise en page dans le flux de travail de traduction de documents.

Lorsque je traitais un PDF, j'ai clairement vu que le tableau se trouvait sur le côté droit de la page, mais que les coordonnées extraites pointaient vers le coin supérieur gauche, ou que le bloc de couleur en surbrillance tombait vers la position d'en-tête. Ce type de problème n'est souvent pas un bug de la bibliothèque d'analyse, mais une incohérence entre le système de coordonnées du PDF et le rendu visuel. Cet article est destiné aux développeurs qui ont besoin de positionner du texte, de faire correspondre des zones ou de dessiner des annotations. Il explique comment l'attribut /Rotate provoque un désalignement des coordonnées et utilise la matrice de rotation de PyMuPDF pour terminer la conversion.

Les exemples de cet article sont tous synthétisés en mémoire et aucun fichier réel n'est lu. Avant de traiter des documents importants, veuillez conserver les originaux, puis les examiner un par un en fonction des limites et des éléments d'acceptation du document.

Que dois-je faire si les coordonnées du PDF ne correspondent pas après la rotation ? Conclusion en une phrase

Utilisez Page.rotation_matrix pour convertir les coordonnées non pivotées en coordonnées d'affichage et vérifiez page.rotation page par page avant le traitement. Ne présumez pas que les directions des coordonnées de toutes les pages sont cohérentes.

votre situationPratiques recommandéesraison
Les coordonnées du texte extrait ne correspondent pas à la position visuelleMultipliez les coordonnées par Page.rotation_matrix avant de tracerPar défaut, les coordonnées du texte sont renvoyées par rapport à la page non pivotée.
Besoin de mapper la position du clic sur les coordonnées d'origineUtilisez Page.derotation_matrix pour la conversion inverseCette matrice effectue la transformation inverse des coordonnées d'affichage en coordonnées non pivotées
Dimension décalage global distance fixeVérifiez CropBox et MediaBox, compensez avec page.cropbox_positionUne incohérence entre les deux origines entraînera un décalage fixe
Les pages pivotent sous différents angles dans le même documentLire page.rotation page par page, ne pas multiplexer la matrice globalementL'état de rotation des différentes pages peut être différent
Disposition complexe (plusieurs colonnes mélangées et graphiques partiellement pivotés)Suspendez le processus automatique et passez au jugement manuelLa validation automatique peut échouer sur ces pages

Comprendre la différence entre l'espace non pivoté et l'espace affiché

Les pages PDF peuvent porter l'attribut /Rotate avec des valeurs de 0, 90, 180 ou 270 degrés. Cette rotation est automatiquement appliquée lors du rendu du lecteur, mais les coordonnées du flux de contenu de la page sont toujours basées sur la MediaBox d'origine non pivotée. Si vous utilisez directement les coordonnées originales extraites pour le dessin ou la correspondance de zones, les résultats seront mal alignés.

PyMuPDF fait clairement la distinction entre ces deux systèmes de coordonnées à partir de la v1.17.0 :

  • Espace non pivoté : Les coordonnées de Page.get_text(), Page.get_image_bbox() et de tous les objets d'annotation sont renvoyées par défaut par rapport à la page non pivotée.
  • Espace d'affichage : seuls Page.rect et Page.bound() refléteront la taille réelle de l'affichage après la rotation.

Cette conception maintient l’extraction de contenu stable. Même si l'angle de rotation de la page est modifié, les coordonnées d'extraction du même texte ne changeront pas. Mais lorsque vous devez ramener les coordonnées sur la page ou les aligner avec des interactions visuelles telles que des clics de souris, vous devez effectuer la transformation des coordonnées manuellement.

PyMuPDF fournit deux matrices clés :

  1. Page.rotation_matrix : convertissez les coordonnées non pivotées en coordonnées affichées.
  2. Page.derotation_matrix : effectuez une opération inverse.

Ces deux matrices encapsulent les transformations de translation et de rotation, de sorte que les développeurs n'ont pas besoin d'écrire manuellement les calculs de fonctions trigonométriques.

Exemple de synthèse : attentes correctes et incorrectes de la transformation de coordonnées

Pour démontrer ce mécanisme, nous construisons une scène synthétique purement en mémoire qui ne repose pas sur des fichiers externes. Si vous devez tester un document réel, veuillez préparer à l'avance un PDF avec l'attribut /Rotate=90 et assurez-vous que sa CropBox est cohérente avec la MediaBox pour éliminer l'interférence du décalage de recadrage.

Paramètres d'entrée : Créez une page portrait A4 (595 x 842 pt), définissez /Rotate = 90. Dans l'espace sans rotation, le point (100, 100) est situé près du coin supérieur gauche ; lors d'une rotation de 90 degrés, la position visuelle du point change considérablement car le système de coordonnées tourne avec lui.

Sortie correcte attendue : multipliez (100, 100) par rotation_matrix et les coordonnées d'affichage résultantes doivent se situer dans les limites valides de la page pivotée (c'est-à-dire page.rect). Pour la page A4 par défaut pivotée de 90 degrés dans le sens inverse des aiguilles d'une montre, le point du coin supérieur gauche d'origine doit être situé près du coin inférieur gauche de l'espace d'affichage, c'est-à-dire que la coordonnée x est plus grande et la coordonnée y est proche de 0. La valeur spécifique dépend de la définition d'origine de la MediaBox. Ne supposez pas simplement que y est supérieur à x.

Gestion des cas limites : lorsque l'angle de rotation est de 0, rotation_matrix doit être la matrice d'identité. Si une valeur de rotation qui n'est pas un multiple de 90 degrés est transmise, PyMuPDF la normalisera généralement, mais il est toujours recommandé de vérifier la validité de la matrice pour éviter de générer des coordonnées NaN.

Python implémente une logique de vérification des coordonnées

L'exemple suivant montre comment vérifier les transformations de coordonnées en mémoire. Il démontre uniquement la logique de fonctionnement matricielle et ne constitue pas un pipeline de traitement PDF complet. Veuillez vous assurer que PyMuPDF est installé avant de l'exécuter et exécutez-le dans un environnement où vous avez verrouillé les dépendances.

import fitz  # PyMuPDF

def validate_rotation_transform():
    """合成示例:验证旋转矩阵在未旋转坐标与显示坐标间的转换"""
    doc = fitz.open()  # 空文档,无需文件路径
    page = doc.new_page(width=595, height=842)

    # 设置页面旋转90度,模拟横向显示的PDF
    page.set_rotation(90)

    # 定义一个在未旋转空间中的测试点 (左上角附近)
    unrotated_point = fitz.Point(100, 100)

    # 获取旋转矩阵并执行变换
    mat = page.rotation_matrix
    display_point = unrotated_point * mat

    # 验证1: 变换后的点必须位于旋转后的页面可视区域内
    assert page.rect.contains(display_point), (
        f"变换后坐标 {display_point} 超出显示边界 {page.rect}"
    )

    # 验证2: 对于默认A4逆时针旋转90度,原(100,100)应变为左下角
    # 即 x 接近页宽(842),y 接近 0。注意:此处纠正了常见的 y>x 误区
    assert display_point.x > 500 and display_point.y < 200, (
        f"90度旋转预期左下角,实际得到 ({display_point.x:.1f}, {display_point.y:.1f})"
    )

    # 验证3: 逆变换可精确恢复原始坐标
    inv_mat = page.derotation_matrix
    recovered = display_point * inv_mat
    assert abs(recovered.x - unrotated_point.x) < 0.01
    assert abs(recovered.y - unrotated_point.y) < 0.01

    doc.close()
    print("坐标变换逻辑校验通过(合成数据)")

# 请在本地环境运行,不要假设线上环境已安装fitz
validate_rotation_transform()

Ce code ne lit aucun fichier réel, mais construit l'état de la page en mémoire. L'instruction assert vérifie la rationalité de la relation mathématique, et non son exactitude commerciale. Un débogage supplémentaire peut être nécessaire si le PDF réel contient une MediaBox non standard ou des transformations imbriquées.

📊 Comparaison de base

Article comparatifespace non tournéespace d'affichage
Sources typiquesget_text(), get_image_bbox(), coordonnées d'annotationPage.rect,Page.bound()
donnée de coordonnéesLa largeur et la hauteur de la MediaBox d'origineTaille d'affichage réelle après rotation
Utilisations courantesExtraction de contenu, journalisation de zone stableDessinez des annotations et alignez-les avec la position du clic
Méthode de conversionMultiplier par rotation_matrixMultiplier par derotation_matrix pour restaurer

Critères d'acceptation et limites de révision manuelle

Ce n’est pas parce que le code peut transmettre l’assertion que l’environnement de production est infaillible. Le tableau suivant répertorie les exceptions courantes et leurs décisions de traitement pour aider à distinguer les scénarios qui peuvent être automatisés et nécessitent une intervention manuelle.

Observer les phénomènesRaisons possiblesdécision de traitement
Dimension décalage global distance fixeLes origines de CropBox et MediaBox sont incohérentesUtilisez page.cropbox_position pour compenser le décalage
Après rotation, les coordonnées du texte sont normales mais l'image est mal alignée.L'image utilise une matrice de transformation CTM indépendanteUtilisez get_image_rects() au lieu de get_image_bbox()
Certaines pages pivotent correctement et d’autres mal.Le document mélange des pages avec différents angles de rotationVérifiez page.rotation page par page, désactivez la matrice de cache globale
Après transformation, les coordonnées dépassent la limite de la page.Le contenu original lui-même est rogné ou possède des coordonnées négativesMarquer comme page anormale et transférer vers la révision manuelle
La page à 0 degré n'a pas besoin d'être transformée mais présente toujours des écartsMétadonnées de rotation cachées écrites par des outils tiersForcer l'appel de remove_rotation() pour réinitialiser puis traiter

Ce tableau traite uniquement de la logique de transformation de coordonnées et ne couvre pas les problèmes de précision de l'OCR ou d'encodage des polices. En cas de composition complexe, la vérification automatique peut échouer. À ce stade, le pipeline doit être mis en pause et un jugement manuel doit être fait pour savoir s'il doit continuer.

Utilisez des listes de contrôle pour la traduction de documents

Avant la traduction, confirmez l'ordre des pages, l'emplacement de la source et l'intégrité du texte, puis soumettez le même échantillon désensibilisé au processus de traduction. Après la traduction, vous devez toujours vérifier si le titre, le texte et les illustrations correspondent correctement, et pas seulement si la traduction est fluide.

OmniDoc (portail produit) fournit un portail de traduction de documents multiformat et le site officiel présente des fonctions d'OCR, de glossaire et de comparaison bilingue. Pour les équipes qui souhaitent travailler directement à partir des fichiers, il s’agit d’une voie qui mérite d’être évaluée avec des échantillons réels. Veuillez utiliser les fichiers désensibilisés que vous êtes autorisé à télécharger et utilisez les éléments de vérification de cet article pour examiner les résultats. Rien ne prétend qu'OmniDoc utilise les bibliothèques open source ou les algorithmes internes mentionnés dans cet article, et l'exemple ne remplace pas non plus les tests de performances du produit.

Lectures complémentaires :

🎯 Quelle méthode vous convient ?

Si vous devez ramener les coordonnées du texte extrait sur la page

Utilisez d'abord rotation_matrix pour convertir en coordonnées d'affichage, puis dessinez des surbrillances ou des annotations.

Si vous devez mapper les clics de souris sur le contenu d'origine

Utilisez derotation_matrix pour la conversion inverse et vérifiez si le point se situe dans la plage valide par rapport à page.rect.

Si vous traitez des documents avec des angles de rotation mixtes

Lisez page.rotation page par page, ne réutilisez pas la matrice globale et marquez les pages hors limites.

Si votre page contient des mises en page complexes ou des graphiques partiellement pivotés

Examinez d’abord des échantillons synthétiques et des échantillons réels à petite échelle, puis décidez s’il faut les transmettre au processus automatique. Lorsque vous rencontrez des anomalies, confiez-les à un examen manuel.

❓ Questions fréquemment posées (FAQ)

1. Pourquoi les coordonnées renvoyées par get_text() ne correspondent-elles pas à la position visuelle ?

Étant donné que ces API renvoient par défaut la page non pivotée, l'attribut /Rotate est appliqué lors du rendu du lecteur.

2. Les données de coordonnées de Page.rect et de get_text() sont-elles identiques ?

non pareil. Page.rect et Page.bound() reflètent la taille d'affichage pivotée, tandis que les coordonnées des API telles que get_text() sont ancrées à la largeur et à la hauteur d'origine non pivotées.

3. La conversion est-elle toujours nécessaire lorsque l'angle de rotation est de 0 ?

inutile. À ce stade, rotation_matrix devrait être une matrice d'identité, mais il est toujours recommandé de vérifier les biais, car des outils tiers peuvent écrire des métadonnées de rotation cachées.

4. Le code peut-il être utilisé directement pour la production après avoir passé l'assertion ?

Non recommandé. L'assertion vérifie uniquement la rationalité des relations mathématiques. Le PDF réel peut contenir une MediaBox non standard, une transformation CTM indépendante ou des pages anormales, qui doivent encore être examinées élément par élément selon le formulaire d'acceptation.

📝Résumé

La source du désalignement des coordonnées réside dans la différence entre l’espace non pivoté et l’espace d’affichage. En utilisant rotation_matrix et derotation_matrix pour la conversion, combinés à une inspection page par page et à un examen manuel, le risque peut être contrôlé dans une plage vérifiable.

Essayez-le maintenant : téléchargez le document pour lancer la traduction, en conservant la mise en page d'origine.

Mis à jour le 2026-11-13