Kozea / WeasyPrint

The awesome document factory
https://weasyprint.org
BSD 3-Clause "New" or "Revised" License
7.17k stars 680 forks source link

Producing destinations with bounding boxes (FitR) rather than coords (XYZ) #2280

Open jambudipa opened 3 days ago

jambudipa commented 3 days ago

So I should not have closed this issue, I have follow up questions...

I would like to know how if anyone has had success creating destination types other than /XYZ? I need to indicate the bounding box of elements, and of course /XYZ does not support that.

I am guessing I have to tinker with this call to provide a bounding box?

liZe commented 4 hours ago

I think that there’s no real advantage for WeasyPrint to use other destination types than /XYZ, as its goal is to always make links lead to hit boxes, which are always border boxes.

But if your goal is to "hack" the PDF, you have two solutions:

jambudipa commented 3 hours ago

Well I'm not sure what you mean, because /XYZ is a point, rather than a bounding box.

I achieved what I needed anyway updating these two functions:

def add_links(links_and_anchors, matrix, pdf, page, names, mark):
    // ...
    for anchor in anchors:
        anchor_name, x1, y1, x2, y2 = anchor
        x1, y1 = matrix.transform_point(x1, y1)
        x2, y2 = matrix.transform_point(x2, y2)
        names.append([
            anchor_name, pydyf.Array([page.reference, '/FitR', x1, y1, x2, y2])])

def resolve_links(pages):
    anchors = set()
    paged_anchors = []
    for i, page in enumerate(pages):
        paged_anchors.append([])
        for anchor_name, (point_x1, point_y1, point_x2, point_y2) in page.anchors.items():
            if anchor_name not in anchors:
                paged_anchors[-1].append((anchor_name, point_x1, point_y1, point_x2, point_y2))
                anchors.add(anchor_name)
    for page in pages:
        page_links = []
        for link in page.links:
            link_type, anchor_name, _, _ = link
            if link_type == 'internal':
                if anchor_name not in anchors:
                    LOGGER.error(
                        'No anchor #%s for internal URI reference',
                        anchor_name)
                else:
                    page_links.append(link)
            else:
                # External link
                page_links.append(link)
        yield page_links, paged_anchors.pop(0)

Now this produced /FitR bounding rectangles, which is precisely what I need.

liZe commented 3 hours ago

Well I'm not sure what you mean, because /XYZ is a point, rather than a bounding box.

What I mean is that for a browser or a PDF reader, reaching an anchor is actually reaching the top-left corner of the border box, which is a point.

Now this produced /FitR bounding rectangles, which is precisely what I need.

Cool for you! What’s your use case?