set_toc alters link coordinates for some rotated pages on pymupdf 1.24.2 (original) (raw)

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

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

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