3

次のコードは、指定した使用可能な高さに収まるまで、reportlab Platypus のフロー可能なテキストのフォント サイズを変更しようとします。しかし、Paragraph flowable が再帰の各ループで style.fontSize 属性を保存しておらず、Python が無限再帰でボークしていることがわかります。

def fits_space(w,h,aW,aH,p):
    """
    Determines if inputted text fits in the space given for a paragraph
    and if it doesn't, reduces the font-size until it does.

    """
    if w<=aW and h<=aH:
        # return font size to apply it to the para again
        print "final font_size: %d" % p.style.fontSize
        return p # now render the paragraph in the doctemplate
    else: 
        p.style.fontSize -= 1
        w,h = p.wrap(aW, aH)
        fits_space(w,h,aW,aH,p)

def renderPage(name, text):
    doc = SimpleDocTemplate("%s.pdf" % name)
    parts = []
    style = ParagraphStyle(name='fancy')
    style.fontSize = 150
    p = Paragraph(text, style)
    aW = PAGE_WIDTH-4*inch  # available width and height 
    aH = PAGE_HEIGHT-4*inch 
    w,h = p.wrap(aW, aH) # find required space
    p = fits_space(w,h,aW,aH,p) # recursively fit the font size to the text
    parts.append(p)
    doc.build(parts)

誰かが私に理由を教えてもらえますか-fits_space()関数のelse句で、p.wrap(aW、aH)を呼び出すと、出力された値は段落のfontSizeを1減らす前と同じですか? フォントサイズを小さくすると、ラップされた高さが小さくなるはずです。

私が間違っているアイデアはありますか?

UPDATE Nitzie の以下のコードは、私の場合も style.leading にリサイザーを追加するために必要なだけでほとんど機能しました。

def shrink_font_size(aW, aH, text, style):
    """Shrinks font size by using pdfmetrics to calculate the height
    of a paragraph, given the font name, size, and available width."""
    def break_lines(text, aW):
        # simpleSplit calculates how reportlab will break up the lines for
        # display in a paragraph, by using width/fontsize.
        return simpleSplit(text, style.fontName, style.fontSize, aW)

    def line_wrap(lines, style):
        # Get overall width of text by getting stringWidth of longest line
        width = stringWidth(max(lines), style.fontName, style.fontSize)
        # Paragraph height can be calculated via line spacing and number of lines.
        height = style.leading * len(lines)
        return width, height

    lines = break_lines(text, aW)
    width, height = line_wrap(lines, style)

    while height > aH or width > aW:
        style.fontSize -= 1
        style.leading -= 1 # do this if you're leading is based on the fontSize
        lines = break_lines(text, aW)
        width, height = line_wrap(lines, style)

ティア

4

1 に答える 1

5

何らかの理由で、p.wrap一度呼び出した後にフォントサイズを変更すると、実際には高さ/幅が再計算されないようです。

stringWidthReportLabとsplitLinesメソッドに基づいてフォント サイズを計算することで、動作するバージョンを取得できました。これはもはや再帰的ではないことを意味しますが:

from reportlab.platypus import SimpleDocTemplate
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.pagesizes import A4
from reportlab.platypus import Paragraph
from reportlab.lib.utils import simpleSplit
from reportlab.pdfbase.pdfmetrics import stringWidth

def shrink_font_size(aW, aH, text, style):
    """Shrinks font size by using pdfmetrics to calculate the height
    of a paragraph, given the font name, size, and available width."""
    def break_lines(text, aW):
        # simpleSplit calculates how reportlab will break up the lines for
        # display in a paragraph, by using width/fontsize.
        return simpleSplit(text, style.fontName, style.fontSize, aW)

    def line_wrap(lines, style):
        # Get overall width of text by getting stringWidth of longest line
        width = stringWidth(max(lines), style.fontName, style.fontSize)
        # Paragraph height can be calculated via line spacing and number of lines.
        height = style.leading * len(lines)
        return width, height

    lines = break_lines(text, aW)
    width, height = line_wrap(lines, style)

    while height > aH or width > aW:
        style.fontSize -= 1
        lines = break_lines(text, aW)
        width, height = line_wrap(lines, style)


def renderPage(name, text):
    doc = SimpleDocTemplate("%s.pdf" % name)
    parts = []
    # Wasn't sure where PAGE_WIDTH and PAGE_HEIGHT came from for OP,
    # so I just used a standard A4 page measurement.
    PAGE_WIDTH, PAGE_HEIGHT = A4
    aW = PAGE_WIDTH - 4*inch  # available width and height 
    aH = PAGE_HEIGHT - 4*inch

    style = ParagraphStyle(name='fancy')
    style.fontSize = 200
    style.leading = 20
    shrink_font_size(aW, aH, text, style)

    p = Paragraph(text, style)
    parts.append(p)
    doc.build(parts)

if __name__ == "__main__":
    renderPage('test', '12345689019283382848248284 842828428529392381472754 842828428529392381472754 842828428529392381472754\n' * 10)
于 2013-02-06T03:11:48.613 に答える