jorisschellekens / borb

borb is a library for reading, creating and manipulating PDF files in python.

Home Page:https://borbpdf.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BUG: HeaderFooterMultiColumnLayout header_height accounted for twice in vertical_margin_top calculation

Aloz1 opened this issue · comments

Describe the bug
It seems that HeaderFooterMulticolumnLayout is not placing the header where I would expect it to. It appears that the class is accounting for the header height twice, rather than once. When vertical margin is set to 0, the y position of the rect passed to the header function is not positioned at the very top of the page. Instead, it is offset by header_height.

_header_height is added to the vertical margin here:

self._vertical_margin_top += self._header_height

So on this line, _header_height is effectively considered twice, as its already considered as part of _vertical_margin_top:

self._page_height - self._vertical_margin_top - self._header_height,

Same goes for this part here:

self._page_height - self._vertical_margin_top - self._header_height,

To Reproduce
Steps to reproduce the behaviour:

from borb.pdf import Alignment, Document, Heading, Page, Paragraph, PDF, HexColor
from borb.pdf.page.page_size import PageSize
from borb.pdf.canvas.layout.page_layout.header_footer_multi_column_layout import HeaderFooterMultiColumnLayout as Layout
from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation


def draw_header(page, rect):
    page.add_annotation(SquareAnnotation(rect, stroke_color=HexColor('#ff0000')))
    heading = Heading("A Test Heading",
                      horizontal_alignment=Alignment.CENTERED,
                      vertical_alignment=Alignment.MIDDLE,
                      margin_top=0,
                      margin_bottom=0)
    heading.paint(page, rect)

class DebugParagraph(Paragraph):
    def paint(self, page, rect):
        page.add_annotation(SquareAnnotation(rect, stroke_color=HexColor('#ff0000')))
        super().paint(page, rect)

doc = Document()
page = Page(*PageSize.A4_LANDSCAPE.value)

doc.add_page(page)

layout = Layout(page, header_callable=draw_header, vertical_margin=0, header_height=100)
layout.add(DebugParagraph('A test paragraph', margin_top=0, padding_top=0))

with open('test.pdf', 'wb') as fh:
    PDF.dumps(fh, doc)

Expected behaviour
I expected this to position the header at the very top of the page with no margin. Instead, it positions the header at header_height from the top of the page.

Screenshots
Current behavior, as produced by the above example:
Current Behavior

The behavior I would expect with margin_top=0:
Expected behavior

Desktop (please complete the following information):

  • OS: Void Linux
  • borb version 2.1.10 (installed from pip with Python 3.11 into venv)

Note, the second screenshot was produced by removing the additional - self._header_height on lines 85 and 109.

I've changed the class MultiColumnLayout in the upcoming release.
It now has 4 extra parameters:

    def __init__(
        self,
        page: "Page",
        column_widths: typing.List[Decimal] = [],
        footer_paint_method: typing.Optional[typing.Callable[["Page", Rectangle], None]] = None,
        header_paint_method: typing.Optional[typing.Callable[["Page", Rectangle], None]] = None,
        inter_column_margins: typing.List[Decimal] = [],
        margin_bottom: Decimal = Decimal(10),
        margin_left: Decimal = Decimal(10),
        margin_right: Decimal = Decimal(10),
        margin_top: Decimal = Decimal(10),
    ):

The 4 margin_ parameters are only accounted for once. So that ought to fix your problem, as well as make the code more general.