Skip to content

remove_rotation() raises ValueError on widgets with empty/infinite rects #4950

@jesse-mark-stream

Description

@jesse-mark-stream

Description

Page.remove_rotation() raises ValueError: bad rect when a page contains widgets with empty or infinite rects (e.g., invisible signature fields with Rect(0, 0, 0, 0)).

The widget loop in remove_rotation() calls widget.update() without error handling, but widget._validate() raises ValueError("bad rect") if the rect is empty or infinite.

Steps to Reproduce

import fitz

doc = fitz.open()
page = doc.new_page()
page.set_rotation(90)

# Add a widget with a zero-dimension rect (simulating an invisible signature field)
widget = fitz.Widget()
widget.field_type = fitz.PDF_WIDGET_TYPE_SIGNATURE
widget.rect = fitz.Rect(0, 0, 0, 0)
page.add_widget(widget)

page.remove_rotation()  # raises ValueError: bad rect

Expected Behavior

remove_rotation() should skip widgets with invalid rects gracefully, similar to how the link loop in the same method already handles errors:

for link in self.get_links():
    ...
    try:
        self.insert_link(link)
    except Exception:
        pass

Actual Behavior

Traceback (most recent call last):
  File "...", line X, in remove_rotation
    widget.update()
  File "...", line X, in update
    self._validate()
  File "...", line X, in _validate
    raise ValueError("bad rect")
ValueError: bad rect

Root Cause

The rotation inverse matrix transforms degenerate rects into rects that are still degenerate:

  • Rect(0, 0, 0, 0) * rot → e.g., Rect(612.0, 0.0, 612.0, 0.0) — still empty (x0 == x1)
  • FZ_INFINITE_RECT * rot → still infinite (overflow back to sentinel values)

The link loop and annotation loop in remove_rotation() both have guards for this case, but the widget loop does not.

Context

We hit this in production processing medical record PDFs. Scanned documents that have been through OCR or signing workflows often contain invisible signature fields or hidden form fields with zero-dimension rects. When these pages also have /Rotate != 0, remove_rotation() crashes.

Suggested Fix

Wrap widget.update() in a try/except, matching the pattern used for links:

for widget in self.widgets():
    r = widget.rect * rot
    widget.rect = r
    try:
        widget.update()
    except Exception:
        pass

Environment

  • PyMuPDF 1.26.6
  • Python 3.12
  • macOS / Linux (AWS Lambda)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions