Plik PDF wygląda poziomo, ale wyodrębnione współrzędne są błędne: wyjaśnij wyraźnie macierz rotacji

Przeanalizuj problem niedopasowania współrzędnych obróconych stron PDF i szczegółowo wyjaśnij konwersję macierzy między przestrzenią nieobróconą a przestrzenią wyświetlania w PyMuPDF. Zawiera przykłady syntezy pamięci i listy kontrolne akceptacji wyjaśniające, jak używać OmniDoc do oceny efektów przywracania złożonego układu w procesie tłumaczenia dokumentów.

Podczas przetwarzania pliku PDF wyraźnie widziałem, że tabela znajdowała się po prawej stronie strony, ale wyodrębnione współrzędne wskazywały na lewy górny róg lub podświetlony blok kolorów spadł do pozycji nagłówka. Tego typu problem często nie jest błędem w bibliotece analizującej, ale niespójnością między układem współrzędnych pliku PDF a renderowaniem wizualnym. Ten artykuł jest przeznaczony dla programistów, którzy muszą pozycjonować tekst, dopasowywać obszary lub rysować adnotacje. Wyjaśnia, w jaki sposób atrybut /Rotate powoduje przesunięcie współrzędnych i wykorzystuje macierz rotacji PyMuPDF do zakończenia konwersji.

Wszystkie przykłady w tym artykule są syntetyzowane w pamięci i nie są odczytywane żadne rzeczywiste pliki. Przed przystąpieniem do przetwarzania ważnych dokumentów prosimy o zachowanie oryginałów, a następnie przeglądanie ich pojedynczo zgodnie z granicami i pozycjami akceptacji w dokumencie.

Co powinienem zrobić, jeśli współrzędne pliku PDF nie zgadzają się po obróceniu? Wniosek w jednym zdaniu

Użyj Page.rotation_matrix, aby przekonwertować nieobrócone współrzędne na współrzędne wyświetlane i sprawdź page.rotation strona po stronie przed przetwarzaniem. Nie zakładaj, że kierunki współrzędnych wszystkich stron są spójne.

twoja sytuacjaZalecane praktykipowód
Wyodrębnione współrzędne tekstu nie odpowiadają pozycji wizualnejPrzed wykreśleniem pomnóż współrzędne przez Page.rotation_matrixDomyślnie zwracane są współrzędne tekstu względem nieobróconej strony.
Należy zmapować pozycję kliknięcia z powrotem na oryginalne współrzędneDo konwersji odwrotnej użyj Page.derotation_matrixTa macierz wykonuje odwrotną transformację ze współrzędnych wyświetlanych na współrzędne nieobrócone
Wymiar całkowitego przesunięcia o stałej odległościSprawdź CropBox i MediaBox, skompensuj za pomocą page.cropbox_positionNiespójność pomiędzy dwoma źródłami spowoduje stałe przesunięcie
Strony w tym samym dokumencie obracają się pod różnymi kątamiCzytaj page.rotation strona po stronie, nie multipleksuj macierzy globalnieStan rotacji różnych stron może być inny
Złożony układ (wiele kolumn, wykresy mieszane i częściowo obrócone)Wstrzymaj proces automatyczny i przejdź do oceny ręcznejNa takich stronach automatyczna weryfikacja może się nie powieść

Zrozum różnicę między przestrzenią nieobróconą a przestrzenią wyświetlaną

Strony PDF mogą posiadać atrybut /Rotate o wartościach 0, 90, 180 lub 270 stopni. Ten obrót jest automatycznie stosowany podczas renderowania czytnika, ale współrzędne przepływu zawartości strony są nadal oparte na nieobróconym oryginalnym MediaBoxie. Jeśli bezpośrednio użyjesz wyodrębnionych oryginalnych współrzędnych do rysowania lub dopasowywania obszarów, wyniki będą niewyrównane.

PyMuPDF wyraźnie rozróżnia te dwa układy współrzędnych, począwszy od wersji 1.17.0:

  • Nieobrócona przestrzeń: Współrzędne Page.get_text(), Page.get_image_bbox() i wszystkich obiektów adnotacji są domyślnie zwracane względem nieobróconej strony.
  • Przestrzeń wyświetlacza: Tylko Page.rect i Page.bound() będą odzwierciedlać rzeczywisty rozmiar wyświetlacza po obróceniu.

Dzięki takiemu rozwiązaniu ekstrakcja treści jest stabilna. Nawet jeśli kąt obrotu strony zostanie zmodyfikowany, współrzędne wyodrębniania tego samego tekstu nie ulegną zmianie. Jeśli jednak konieczne jest narysowanie współrzędnych z powrotem na stronę lub wyrównanie ich za pomocą interakcji wizualnych, takich jak kliknięcia myszą, należy ręcznie przeprowadzić transformację współrzędnych.

PyMuPDF udostępnia dwie kluczowe macierze:

  1. Page.rotation_matrix: Konwertuj nieobrócone współrzędne na współrzędne wyświetlane.
  2. Page.derotation_matrix: Wykonaj operację odwrotną.

Te dwie macierze zawierają transformacje translacji i rotacji, więc programiści nie muszą ręcznie pisać obliczeń funkcji trygonometrycznych.

Przykład syntezy: Poprawne i nieprawidłowe oczekiwania dotyczące transformacji współrzędnych

Aby zademonstrować ten mechanizm, konstruujemy czysto syntetyczną scenę w pamięci, która nie opiera się na plikach zewnętrznych. Jeśli chcesz przetestować prawdziwy dokument, przygotuj wcześniej plik PDF z atrybutem /Rotate=90 i upewnij się, że jego CropBox jest zgodny z MediaBox, aby wyeliminować zakłócenia przesunięcia kadrowania.

Ustawienia wejściowe: Utwórz stronę A4 pionowo (595 x 842 pkt), ustaw /Rotate = 90. W przestrzeni nieobróconej punkt (100, 100) znajduje się w pobliżu lewego górnego rogu; po obróceniu o 90 stopni wizualna pozycja punktu zmienia się znacząco, ponieważ układ współrzędnych obraca się wraz z nim.

Oczekiwano prawidłowego wyniku: Pomnóż (100, 100) przez rotation_matrix, a wynikowe współrzędne wyświetlania powinny mieścić się w prawidłowych granicach obróconej strony (tj. page.rect). W przypadku domyślnej strony A4 obróconej o 90 stopni przeciwnie do ruchu wskazówek zegara, pierwotny lewy górny róg powinien znajdować się w pobliżu lewego dolnego rogu przestrzeni wyświetlania, czyli współrzędna x jest większa, a współrzędna y bliska 0. Konkretna wartość zależy od definicji początku MediaBoxa. Nie zakładaj po prostu, że y jest większe niż x.

Obsługa przypadków granicznych: Gdy kąt obrotu wynosi 0, rotation_matrix powinno być macierzą tożsamości. Jeśli zostanie przekazana wartość obrotu, która nie jest wielokrotnością 90 stopni, PyMuPDF zwykle ją znormalizuje, ale nadal zaleca się sprawdzenie ważności macierzy, aby uniknąć generowania współrzędnych NaN.

Python implementuje logikę weryfikacji współrzędnych

Poniższy przykład pokazuje, jak sprawdzić transformacje współrzędnych w pamięci. Pokazuje jedynie logikę operacji na macierzy i nie jest kompletnym potokiem przetwarzania plików PDF. Przed uruchomieniem upewnij się, że PyMuPDF jest zainstalowany i uruchom go w środowisku, w którym masz zablokowane zależności.

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()

Ten kod nie czyta żadnego prawdziwego pliku, ale konstruuje stan strony w pamięci. Instrukcja assert sprawdza racjonalność zależności matematycznej, a nie poprawność biznesową. Jeśli rzeczywisty plik PDF zawiera niestandardowe przekształcenia MediaBox lub zagnieżdżone, może być wymagane dodatkowe debugowanie.

📊 Porównanie rdzeni

Pozycja porównawczanieobrócona przestrzeńprzestrzeń wystawową
Typowe źródłaget_text(), get_image_bbox(), współrzędne adnotacjiPage.rect,Page.bound()
układ współrzędnychSzerokość i wysokość oryginalnego MediaBoxaRzeczywisty rozmiar wyświetlacza po obróceniu
Typowe zastosowaniaEkstrakcja treści, stabilne rejestrowanie strefNarysuj adnotacje i dopasuj je do pozycji kliknięcia
Metoda konwersjiPomnóż przez rotation_matrixAby przywrócić, pomnóż przez derotation_matrix

Kryteria akceptacji i granice ręcznego przeglądu

To, że kod może przekazać asercję, nie oznacza, że środowisko produkcyjne jest niezawodne. W poniższej tabeli wymieniono typowe wyjątki i decyzje dotyczące ich obsługi, aby pomóc rozróżnić scenariusze, które można zautomatyzować i wymagają ręcznej interwencji.

Obserwuj zjawiskaMożliwe przyczynydecyzja o przetwarzaniu
Wymiar całkowitego przesunięcia o stałej odległościPoczątki CropBox i MediaBox są niespójneUżyj page.cropbox_position, aby skompensować przesunięcie
Po obrocie współrzędne tekstu są normalne, ale obraz jest źle wyrównany.Obraz wykorzystuje niezależną macierz transformacji CTMUżyj get_image_rects() zamiast get_image_bbox()
Niektóre strony są obrócone prawidłowo, inne nieprawidłowo.Dokument zawiera strony o różnych kątach obrotuSprawdź page.rotation strona po stronie, wyłącz globalną macierz pamięci podręcznej
Po transformacji współrzędne przekraczają granicę strony.Sama oryginalna treść jest przycięta lub ma ujemne współrzędneOznacz jako nieprawidłową stronę i przenieś do ręcznego sprawdzenia
Strona 0 stopni nie wymaga przekształcenia, ale nadal zawiera odchyleniaUkryte metadane rotacji zapisane przez narzędzia innych firmWymuś wywołanie remove_rotation() w celu zresetowania, a następnie przetworzenia

Ta tabela dotyczy jedynie logiki transformacji współrzędnych i nie obejmuje problemów z dokładnością OCR ani kodowaniem czcionek. W przypadku skomplikowanego składu automatyczna weryfikacja może się nie powieść. Na tym etapie należy wstrzymać prace nad rurociągiem i ręcznie podjąć decyzję, czy kontynuować.

Użyj list kontrolnych do tłumaczenia dokumentów

Przed tłumaczeniem sprawdź kolejność stron, lokalizację źródła i integralność tekstu, a następnie prześlij tę samą pozbawioną czułości próbkę do procesu tłumaczenia. Po tłumaczeniu nadal musisz sprawdzić, czy tytuł, tekst i ilustracje są ze sobą zgodne, a nie tylko, czy tłumaczenie jest płynne.

OmniDoc (portal produktowy) udostępnia wieloformatowy portal do tłumaczenia dokumentów, a oficjalna strona internetowa zawiera funkcje OCR, glosariusza i porównywania dokumentów dwujęzycznych. Dla zespołów, które chcą pracować bezpośrednio z plików, jest to ścieżka warta sprawdzenia na przykładach z życia wziętych. Użyj plików pozbawionych zabezpieczeń, do przesłania których masz pozwolenie, i skorzystaj z elementów zaznaczonych w tym artykule, aby sprawdzić wyniki. Nie ma twierdzenia, że OmniDoc korzysta z bibliotek open source lub wewnętrznych algorytmów wspomnianych w tym artykule, ani też przykład nie zastępuje testowania wydajności produktu.

Dalsza lektura:

🎯 Która metoda jest dla Ciebie odpowiednia?

Jeśli chcesz narysować wyodrębnione współrzędne tekstu z powrotem na stronę

Najpierw użyj rotation_matrix, aby przekonwertować na współrzędne wyświetlane, a następnie narysuj wyróżnienia lub adnotacje.

Jeśli chcesz zmapować kliknięcia myszą z powrotem na oryginalną treść

Użyj derotation_matrix do konwersji odwrotnej i sprawdź, czy punkt mieści się w prawidłowym zakresie względem page.rect.

Jeśli masz do czynienia z dokumentami o różnych kątach obrotu

Czytaj page.rotation strona po stronie, nie używaj ponownie macierzy globalnej i zaznacz strony wykraczające poza granice.

Jeśli Twoja strona zawiera złożone układy lub częściowo obrócone wykresy

Najpierw przejrzyj próbki syntetyczne i próbki rzeczywiste o małej skali, a następnie zdecyduj, czy przekazać je do automatycznego procesu. W przypadku napotkania nieprawidłowości należy je przekazać do ręcznego przeglądu.

❓ Często zadawane pytania (FAQ)

1. Dlaczego współrzędne zwracane przez get_text() są niezgodne z pozycją wizualną?

Ponieważ te interfejsy API domyślnie zwracają dane względem nieobróconej strony, podczas renderowania czytnika stosowany jest atrybut /Rotate.

2. Czy punkty odniesienia Page.rect i get_text() są takie same?

nie to samo. Page.rect i Page.bound() odzwierciedlają rozmiar obróconego wyświetlacza, podczas gdy współrzędne interfejsów API, takich jak get_text(), są zakotwiczone w oryginalnej, nieobróconej szerokości i wysokości.

3. Czy konwersja jest nadal konieczna, gdy kąt obrotu wynosi 0?

niepotrzebny. W tym momencie rotation_matrix powinna być macierzą tożsamości, ale nadal zaleca się sprawdzenie pod kątem stronniczości, ponieważ narzędzia innych firm mogą zapisywać ukryte metadane rotacji.

4. Czy po zatwierdzeniu asercji kod można wykorzystać bezpośrednio do produkcji?

Niezalecane. Twierdzenie sprawdza jedynie racjonalność zależności matematycznych. Rzeczywisty plik PDF może zawierać niestandardowy MediaBox, niezależną transformację CTM lub nieprawidłowe strony, które nadal należy przeglądać element po elemencie zgodnie z formularzem akceptacji.

📝 Podsumowanie

Źródłem niewspółosiowości współrzędnych jest różnica pomiędzy przestrzenią nieobróconą a przestrzenią wyświetlania. Używając rotation_matrix i derotation_matrix do konwersji, w połączeniu z inspekcją strona po stronie i przeglądem ręcznym, ryzyko można kontrolować w możliwym do sprawdzenia zakresie.

Wypróbuj teraz: prześlij dokument, aby rozpocząć tłumaczenie, zachowując oryginalny układ

Zaktualizowano 2026-11-13