[Python] ReportLab stringWidth() inconsistency. One bullet point always truncates despite...

Discussão em 'Python' iniciado por Stack, Julho 8, 2025.

  1. Stack

    Stack Membro Participativo

    I have a persistent ReportLab PDF generation issue where exactly one bullet point per document gets truncated, despite extensive debugging and optimization.

    Problem


    Using ReportLab's stringWidth() for pixel-based text wrapping, but certain character sequences consistently cause truncation:

    • "...by 18 points" → "...by 1"
    • "...rates by 40%" → "...rates b"
    • "...recurring revenue" → "...recurrin"
    Current Implementation


    CurrentText Wrapping Logic:

    `def _wrap_text_by_width(self, text: str, max_width: float, font_name: str, font_size: int) -> list: from reportlab.pdfbase.pdfmetrics import stringWidth

    # Measure actual width of text
    text_width = stringWidth(text, font_name, font_size)
    if text_width <= max_width:
    return [text]

    words = text.split()
    lines = []
    current_line = ""

    for word in words:
    test_line = current_line + (" " if current_line else "") + word
    test_width = stringWidth(test_line, font_name, font_size)

    if test_width <= max_width:
    current_line = test_line
    else:
    # Line wrapping logic continues...`


    Key code fixes applied:

    1. ASCII normalization for consistent width calculations


    def _normalize_text_to_ascii(self, text: str) -> str:
    # Convert smart quotes, em-dashes, Unicode bullets to ASCII
    # This fixed 90% of width calculation issues

    2. Conservative margin buffer for bullet points


    wrapped_lines = self._wrap_text_by_width(
    clean_content,
    available_width - 100, # 100px safety margin
    "Helvetica",
    body_font_size


    )

    What I've Tried

    • ASCII normalization (fixed 90% of issues)
    • Conservative margins (30px to 150px tested)
    • Alternative PDF libraries (WeasyPrint, pdfkit)
    • Smart text breaking logic
    • Character-based vs pixel-based wrapping
    • Different font families
    Question


    Is there a known issue with ReportLab's stringWidth() calculation for certain character sequences? What's the most reliable way to ensure accurate text measurements for PDF generation?

    Current success rate: 99%, but that 1% persistent issue is unacceptable for production use.

    Additional Context:

    The issue appears to be fundamental to ReportLab's string measurement system, possibly related to:

    1. Kerning calculations for specific character combinations
    2. Font metrics inconsistencies in Helvetica family
    3. Floating-point precision in width calculations
    4. Character encoding edge cases despite ASCII normalization
    5. Exactly one bullet point will not truncate and will continue off the page.

    Examples of Problematic Text: "...Net Promoter Score (NPS) by 18 points" becomes "...Net Promoter Sc" "...feature adoption rates by 40%" becomes "...feature adoption rates b"
    "...annual recurring revenue" becomes "...annual recurrin"

    The core issue seems to be that ReportLab's stringWidth() function occasionally returns inaccurate measurements for certain character sequences, causing the text wrapping algorithm to break lines at incorrect positions. This results in text being cut off mid-word even with generous margin buffers. [1]: https://i.sstatic.net/fzG8tmv6.png

    Continue reading...

Compartilhe esta Página