pymupdf / PyMuPDF

PyMuPDF is a high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.
https://pymupdf.readthedocs.io
GNU Affero General Public License v3.0
5.09k stars 490 forks source link

Incorrect links to points on pages having different heights #3347

Closed ikseek closed 2 months ago

ikseek commented 5 months ago

Description of the bug

Having a document with pages of a different height I try to create a link from a rectangle on one page to a rectangle on another. When links are created to places on pages of equal heights, all works fine. When links are created to places on pages of different heights, viewers jump to an offset position on that page. Empirically I found that this offset is the difference of source and destination page heights.

Is that intended? In the example I'm attaching, I added a convert function, but why do I need it, shouldn't insert_link calculate it automatically?

To reproduce the problem open the document with higher zoom level (300%) and click rectangles, notice that following links do not bring next rectangle into top-level corner of the viewport. Replace target point (to_rect.top_left) with commented out convert call to see workaround that fixes it. Tested in Mac OS Preview, Chrome PDF and https://mozilla.github.io/pdf.js/web/viewer.html viewers.

How to reproduce the bug

import os

import fitz

def convert(link_page_size, target_page_size, point):
    return fitz.Point(point.x, point.y + link_page_size.y - target_page_size.y)

doc = fitz.open()
doc.new_page(width=500, height=800)
doc.new_page(width=800, height=500)
rects = [
    (0, fitz.Rect(10, 20, 50, 40), fitz.utils.getColor('red')),
    (0, fitz.Rect(300, 350, 400, 450), fitz.utils.getColor('green')),
    (1, fitz.Rect(20, 30, 40, 50), fitz.utils.getColor('blue')),
    (1, fitz.Rect(350, 300, 450, 400), fitz.utils.getColor('black'))
]

for page, rect, color in rects:
    doc[page].draw_rect(rect, color=color)

for (from_page, from_rect, _), (to_page, to_rect, _) in zip(rects, rects[1:] + rects[:1]):
    doc[from_page].insert_link({
        'kind': 1,
        'from': from_rect,
        'page': to_page,
        'to': to_rect.top_left,
        # 'to': convert(doc[from_page].mediabox_size, doc[to_page].mediabox_size, to_rect.top_left),
    })

doc.save("out.pdf")
os.system("open out.pdf")

PyMuPDF version

1.24.1

Operating system

MacOS

Python version

3.12

JorjMcKie commented 5 months ago

You did not provide a reproducer file. The referenced file seems to have all equal page heights.

ikseek commented 5 months ago

Actually I did, the code generates pdf from scratch and page heights are different

julian-smith-artifex-com commented 2 months ago

Thanks for submitting this bug, and for the reproducing code. I've just pushed a fix so this will be fixed in our next release.

julian-smith-artifex-com commented 2 months ago

Fixed in 1.24.6.