Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set_toc alters link coordinates for some rotated pages on pymupdf 1.24.2 #3400

Open
MaelkoM opened this issue Apr 18, 2024 · 0 comments
Open

Comments

@MaelkoM
Copy link

MaelkoM commented Apr 18, 2024

Description of the bug

Hi there!

First of all, I really appreciate this library and its performance and features.
Also, this is my first bug report on github, so I hope it's all right.

Now to the suspected bug:

Coordinates of GOTO links in newly created toc entries get altered when confronted with some rotated pages.
If a page is rotated by 270° (plus multiples of 360°), the given coordinates in links specified in new toc entries change after setting the new toc. This results in the links pointing to wrong positions.

Thanks!

How to reproduce the bug

  • Open or create a pdf document with a page that is rotated by 270°
  • Add toc entry with GOTO link to some coordinates on the rotated page
  • Set the new toc
  • Save document

Minimal Script

import fitz

width = 75
height = 111
circle_middle_point = fitz.Point(height / 4, width / 4)

with fitz.open() as doc:

    page = doc.new_page(width=width, height=height)
    page.set_rotation(270)
    # draw a circle at the middle point to facilitate debugging
    page.draw_circle(circle_middle_point, color=(0, 0, 1), radius=5, width=2)
    # rotate the middle point by the page rotation for the new toc entry
    toc_link_coords = circle_middle_point * page.rotation_matrix
    toc = [
        (
            1,
            "broken link to circle",
            1,
            {
                "kind": fitz.LINK_GOTO,
                "page": 0,
                "to": toc_link_coords,
            },
        )
    ]
    doc.set_toc(toc)  # set the toc
    doc.save(f"270_rotation_test_with_toc.pdf")

Additional info

  • Tested with python 3.10 and pymupdf 1.24.2 but I first noticed it a few months ago.
  • Tested on Windows 10/11 and Ubuntu 22 on different Intel and AMD CPUs
  • A fudge factor of (page height - page width) applied to the link coordinates can correct whatever miscalculation happens while setting the toc.

Example Script

The following example script implements this fudge factor and creates a document with multiple rotated pages:

import fitz

paper_size = fitz.paper_size("A4")
width = paper_size[0]
height = paper_size[1]

f_factor = height - width  # fudge factor

box_coords = (0, 0, paper_size[0] / 2, paper_size[1] / 2)
box_rect = fitz.Rect(box_coords)
middle_point = fitz.Point(
    (box_coords[0] + box_coords[2]) / 2, (box_coords[1] + box_coords[3]) / 2
)

toc = []
true_toc_link_coords = []

with fitz.open() as doc:

    for i in range(8):
        page = doc.new_page(width=width, height=height)
        page.insert_textbox(
            fitz.Rect(box_coords),
            buffer=f"page {i+1}\n{i * 90}° rotation",
            align=fitz.TEXT_ALIGN_CENTER,
            fontsize=50,
        )
        page.draw_rect(
            box_rect, color=(0, 1, 0), width=1
        )  # draw a rectangle to facilitate debugging

        # draw a circle at the middle point to facilitate debugging
        page.draw_circle(middle_point, color=(0, 0, 1), radius=10, width=5)

        page.set_rotation(90 * i)  # rotate the page by i * 90 degrees

        # rotate the middle point by the page rotation for the new toc entry
        toc_middle_point = middle_point * page.rotation_matrix
        true_toc_link_coords.append(toc_middle_point)

        if (page.rotation + 90) % 360 == 0:
            # fix thecoordinates for pages by subtracting/adding the fudge factor
            toc_middle_point = fitz.Point(
                (toc_middle_point[0] - f_factor, toc_middle_point[1] + f_factor)
            )

        toc.append(
            (
                1,
                f"page {i}",
                i + 1,
                {
                    "kind": fitz.LINK_GOTO,
                    "page": i,
                    "to": toc_middle_point,
                },
            )
        )

    doc.set_toc(toc)  # set the toc
    toc2 = doc.get_toc(simple=False)  # export the toc for debugging

    # show differences in GOTO links before and after setting the toc
    for i in range(len(toc)):
        toc_link_original = toc[i][3]["to"]
        toc_link_new = toc2[i][3]["to"]
        if toc_link_original != toc_link_new:
            print(f"ToC link for page {i + 1} had to be fixed.")
            print(f"desired coords: {true_toc_link_coords[i]}")
            print(f"coords with fudge factor before set_toc: {toc_link_original}")
            print(f"resulting coords after set_toc: {toc_link_new}\n")

    doc.save(f"rotation_test_with_toc.pdf")

PyMuPDF version

1.24.2

Operating system

Windows

Python version

3.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant