From robin at reportlab.com Fri Dec 1 06:12:05 2023 From: robin at reportlab.com (Robin Becker) Date: Fri, 1 Dec 2023 11:12:05 +0000 Subject: [reportlab-users] Long word or URI doesn't wrap inside table cell In-Reply-To: <662F040C-BF46-4D51-A7D3-E7FB0219C6E6@shinefour.de> References: <662F040C-BF46-4D51-A7D3-E7FB0219C6E6@shinefour.de> Message-ID: <1bd256a8-5854-43b7-8b8d-66eceab663c2@everest.reportlab.co.uk> On 30/11/2023 14:00, Manuel Koch wrote: > Creating a table with cells that contain long words doesn?t seem to work as expected, i.e. the words are not wrapped automatically inside the paragraphs and the table cell breaks page layout by being too wide. > Additionally the rendered text of the URI contains strange characters ( ?;? ) that are not in the original text used to create the paragraph. > > How can long word wrapping by controlled for a paragraph inside a table cell ? > > Here is a minimal code ( using macOS Sonoma, arm64, python==3.10, reportlab==3.6.11 ): > Hi Manuel, again thanks for this report. I looked at the _calcPreliminaryWidths code and it seems we need to handle the case when the predicted remaining space is non-positive. I tried this diff which seems to fix your example. It seems obvious that we cannot do anything if the defined column widths exceed the availWidth, but if there is space we can apply it to the unspecified columns proportionately. I'm uncertain as to whether we should just try and scale the totalMinimum/minimums at line 849 to make the if remaining > 0: true. This is simple patch to handle the scaling directly. diff -r 2575e5f684b1 src/reportlab/platypus/tables.py --- a/src/reportlab/platypus/tables.py Mon Nov 13 13:15:30 2023 +0000 +++ b/src/reportlab/platypus/tables.py Fri Dec 01 10:57:32 2023 +0000 @@ -925,8 +925,10 @@ assert adjusted >= minimum W[colNo] = adjusted else: + remaining = availWidth - totalDefined + adj = 1 if remaining<=0 else remaining/totalMinimum for colNo, minimum in minimums.items(): - W[colNo] = minimum + W[colNo] = minimum * adj #if verbose: print('new widths are:', W) self._argW = self._colWidths = W return W > import re > from pathlib import Path > > from reportlab.lib import colors > from reportlab.lib.pagesizes import portrait, A4 > from reportlab.lib.styles import getSampleStyleSheet > from reportlab.lib.units import cm > from reportlab.platypus import Paragraph, TableStyle, Table, Image > > PAGE_SIZE = portrait(A4) > PAGE_MARGIN_TOP = 2 * cm > PAGE_MARGIN_LEFT = 0.7 * cm > PAGE_MARGIN_RIGHT = 0.7 * cm > PAGE_MARGIN_BOTTOM = 1 * cm > PAGE_CONTENT_WIDTH = PAGE_SIZE[0] - PAGE_MARGIN_LEFT - PAGE_MARGIN_RIGHT > PAGE_CONTENT_HEIGHT = PAGE_SIZE[1] - PAGE_MARGIN_TOP - PAGE_MARGIN_BOTTOM > > LEADING_FACTOR = 1.25 > > BODY_TEXT_STYLE_NAME = "BodyText" > BODY_TEXT_FONT_NAME = "Roboto" # you can use "Courier" too, same problem > BODY_TEXT_FONT_SIZE = 12 > > STYLES = getSampleStyleSheet() > BODY_TEXT_STYLE = STYLES[BODY_TEXT_STYLE_NAME] > BODY_TEXT_STYLE.fontName = BODY_TEXT_FONT_NAME > BODY_TEXT_STYLE.fontSize = BODY_TEXT_FONT_SIZE > BODY_TEXT_STYLE.leading = BODY_TEXT_FONT_SIZE * LEADING_FACTOR > BODY_TEXT_STYLE.wordWrap = True # this has no effect whatsoever, commenting it out does not improve anything > BODY_TEXT_STYLE.splitLongWords = True # this has no effect whatsoever, commenting it out does not improve anything > BODY_TEXT_STYLE.uriWasteReduce = 0.0001 # using a greater value make things sometimes even worse > > > def create_pdf(): > output_path = Path.home() / "tmp" / "test.pdf" > doc = DocTemplate( > output_path.as_posix(), > pagesize=PAGE_SIZE, > topMargin=PAGE_MARGIN_TOP, > leftMargin=PAGE_MARGIN_LEFT, > rightMargin=PAGE_MARGIN_RIGHT, > bottomMargin=PAGE_MARGIN_BOTTOM, > showBoundary=True, > ) > paragraphs = [ > Paragraph("Test Text", style=BODY_TEXT_STYLE), > Paragraph( > "Test Text averyveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryvveryveryverylongword", > style=BODY_TEXT_STYLE), > Paragraph( > > "Label: This is text with a long URI https://www.foo.com/hello/world/this/is/a/very/long/website/path/11111/222222/?abc=123&def=756&ghj=888", > style=BODY_TEXT_STYLE), > ] > cells = [ > [ > paragraphs, > [Image(create_placeholder_image(200, 200), width=3.5 * cm, height=3.5 * cm)], > ] > ] > table = Table( > cells, > colWidths=[ > "*", > 4 * cm, > ], > ) > table.setStyle( > TableStyle( > [ > # align image and qr > ("ALIGN", (0, 0), (-1, -1), "CENTER"), > ("VALIGN", (0, 0), (-2, -1), "CENTER"), > ("VALIGN", (-1, 0), (-1, -1), "TOP"), > # force padding > ("TOPPADDING", (0, 0), (-1, -1), 0), > ("BOTTOMPADDING", (0, 0), (-1, -1), 0), > ("LEFTPADDING", (0, 0), (-1, -1), 0), > ("RIGHTPADDING", (0, 0), (-1, -1), 0), > # table borders, for debugging > ("INNERGRID", (0, 0), (-1, -1), 0.25, colors.red), > ("BOX", (0, 0), (-1, -1), 0.25, colors.red), > ] > ) > ) > flowables = [table] > doc.build(flowables) > print(f"Saved {output_path}") > > > if __name__ == "__main__": > create_pdf() > > [cid:5591b93c-b892-4172-bd9b-c8f4878ff8cf at EURP191.PROD.OUTLOOK.COM] > > > _______________________________________________ > reportlab-users mailing list > reportlab-users at lists2.reportlab.com > https://pairlist2.pair.net/mailman/listinfo/reportlab-users -- Robin Becker