为了账号安全,请及时绑定邮箱和手机立即绑定

Python ReportLab 段落计数打印行数

Python ReportLab 段落计数打印行数

宝慕林4294392 2021-12-29 20:07:29
有什么方法可以让我在 reportlab 中获得 Flowable Paragraph 的行数?我有一个用不同大小和字体打印的很长的字符串。我需要知道使用 TA_JUSTIFY 对齐方式打印的整个段落使用了多少行。这能做到吗?下面是我的示例 python 文件import osimport sysimport stringimport pprintimport impimport tempfilefrom reportlab.pdfgen import canvasfrom reportlab.platypus import Preformatted, XPreformatted, Paragraph, Frame, Image, \     Table, TableStyle, Spacerfrom reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFYfrom reportlab.lib import stylesfrom reportlab.lib.styles import getSampleStyleSheet, ParagraphStylefrom reportlab.lib.pagesizes import *from reportlab.lib import colorsimport reportlab.rl_config# Import as may be needed if we require embedded true type fontsfrom reportlab.pdfbase import pdfmetricsfrom reportlab.pdfbase.ttfonts import TTFontfrom reportlab.lib.fonts import addMappingfrom reportlab.graphics.barcode import code39, code128, code93from reportlab.graphics.barcode import commonfrom reportlab.graphics.barcode import qrfrom reportlab.graphics import renderPDFfrom reportlab.graphics.shapes import Drawingimport stringimport osimport impfrom reportlab.lib import colorscanv = canvas.Canvas('Output.pdf')styles = getSampleStyleSheet()parastyle = ParagraphStyle(name='Justify', alignment=TA_JUSTIFY)parastyle.leading = 12parastyle.fontSize = 11styles.add(parastyle)我需要获取段落中打印的行数。在我的例子中,我必须得到 11。如果我更改字体和字体大小,我必须相应地获取值。
查看完整描述

2 回答

?
元芳怎么了

TA贡献1798条经验 获得超7个赞

在你调用Paragraph.wrapor 之后Paragraph.wrapOn,你有一个叫做blParaavailable的属性,它有一个叫做lines列表的属性。你可以使用它的长度。像这样:


from reportlab.lib.enums import TA_JUSTIFY

from reportlab.lib.pagesizes import A4

from reportlab.lib.styles import ParagraphStyle

from reportlab.lib.units import mm

from reportlab.pdfgen.canvas import Canvas

from reportlab.platypus import Paragraph


canvas = Canvas("test.pdf")

drawText = "The Avengers become divided, both over how to approach Loki and the revelation that S.H.I.E.L.D. plans to harness the Tesseract to develop weapons as a deterrent against hostile extraterrestrials. As the group argues, Barton and Loki's other possessed agents attack the Helicarrier, disabling one of its engines in flight and causing Banner to transform into the Hulk. Stark and Rogers work to restart the damaged engine, and Thor attempts to stop the Hulk's rampage. Romanoff reluctantly fights Barton, and knocks him unconscious, breaking Loki's mind control. Loki escapes after killing Coulson and ejecting Thor from the airship, while the Hulk falls to the ground after attacking a S.H.I.E.L.D. fighter jet. Fury uses Coulson's death to motivate the Avengers into working as a team. Stark and Rogers realize that for Loki, simply defeating them will not be enough; he needs to overpower them publicly to validate himself as ruler of Earth. Loki uses the Tesseract, in conjunction with a device Selvig built, to open a wormhole above Stark Tower to the Chitauri fleet in space, launching his invasion."


availWidth, availHeight = 190*mm, A4[1]


style = ParagraphStyle("justifies", alignment=TA_JUSTIFY, fontSize=11, leading=12)

par = Paragraph(drawText, style=style)


par.wrap(availWidth, availHeight)

par.drawOn(canvas, 10*mm, A4[1]-10*mm-par.height)


print(len(par.blPara.lines))  # 11

canvas.save()

还有simpleSplit它做同样的工作,额外的好处是更容易获得每一行的文本。


from reportlab.lib.utils import simpleSplit

lines = simpleSplit(drawText, style.fontName, style.fontSize, availWidth)


查看完整回答
反对 回复 2021-12-29
?
临摹微笑

TA贡献1982条经验 获得超2个赞

我刚刚遇到了这个问题,同时也在寻找一些简单的方法来完成您的要求。不幸的是我没有找到答案,所以我试图把一些东西放在一起来让它工作。它不漂亮,但它有效!


我刚刚在您的 canv.save() 方法调用之后添加了此代码:


pixelRatio = 1.333333 # 1 point = 1.333333 pixels

# https://websemantics.uk/articles/font-size-conversion/

# http://www.endmemo.com/sconvert/pixelpoint.php#targetText=Pixel%E2%86%94Point%201%20Point,Twip%201%20Pixel%20%3D%2015%20Twip


fontLineHeight = styles["Justify"].fontSize * pixelRatio

boxWidth = width

boxHeight = height

boxLines = int(72/fontLineHeight)

boxLRBuffer = 0 # Adjust this to whatever inside margin/padding you have in your box

boxPixelCapacity = boxWidth * boxLines - boxLRBuffer # Total pixels in the box


# A list to hold the lines of text

textLines = []

# A pointer to indicate which character is being evaluated

position = len(drawText)

# Make a copy of the original string so as to not modify it

tempString = drawText

# This is a dummy string used to test the width of the string

testString1 = tempString

# Another dummy string to hold what is not being split into a line

# testString2 will be build going backwards from the last character

# to the character right after the line split

testString2 = ''

# Boolean flag to get out of the while loop

done = False

while not done:

    # Use pdfmetrics to get the line width in points based upon the fontName and fontSize used

    if pdfmetrics.stringWidth(testString1, styles["Justify"].fontName, styles["Justify"].fontSize, 'utf8') > boxWidth-boxLRBuffer*2:

        # Since the line is too long, move backwards through the string until an appropriate size is found

        # by decreasing the pointer position.  Spaces also take space.

        position -= 1

        if position >= 0:

            #since the the pointer has not reached the beginning of testString1

            testString1 = testString1[:position] # remove the last character from testString1

            testString2 = tempString[position:] # add the next character to testString2 for later use

    # Since testString1 now fits within the stringWidth

    # it must be checked to see if this is the last line

    # being processed.

    elif testString1 == testString2:

        # This must be the last line since it equals testString2

            textLines.append(testString2.strip())

            break

    # This is not the last line of text, so now work backwards in

    # the string to find a space so the line can be split

    elif ' ' in testString1:

        while testString1[position:] != ' ' and position >= 0:

            testString1 = testString1[:position]

            testString2 = tempString[position:]

            position -= 1

        if len(testString1):

            textLines.append(testString1.strip())

        else:

            textLines.append(testString2.strip())

            break

        tempString = tempString[position:].strip()

        testString1 = tempString

        position = len(tempString)

    elif testString1 == "":

        # It's done

        break

    else:

        # The text does not exceed the stringWidth

        textLines.append(testString1)

        # testString2 must be checked and if empty then it's done

        if testString2 == "":

            done = True

        else:

           tempString = tempString[position:].strip()

           testString1 = tempString

           position = len(tempString)

print(len(textLines))

我愿意接受使此代码更好或更精简的建议。


查看完整回答
反对 回复 2021-12-29
  • 2 回答
  • 0 关注
  • 355 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号