【问题标题】:Python ReportLab Paragraph Count Lines PrintedPython ReportLab 打印的段落计数行
【发布时间】:2019-08-27 01:36:14
【问题描述】:

有什么方法可以在reportlab 中获取可流动段落的行数? 我有一个很长的字符串,以不同的大小和字体打印。 我需要知道使用 TA_JUSTIFY 对齐方式打印整个段落使用了多少行。

这个可以吗?

下面是我的示例 python 文件

import os
import sys
import string
import pprint
import imp
import tempfile

from reportlab.pdfgen import canvas
from reportlab.platypus import Preformatted, XPreformatted, Paragraph, Frame, Image, \
     Table, TableStyle, Spacer
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
from reportlab.lib import styles
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.pagesizes import *
from reportlab.lib import colors
import reportlab.rl_config
# Import as may be needed if we require embedded true type fonts
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.fonts import addMapping
from reportlab.graphics.barcode import code39, code128, code93
from reportlab.graphics.barcode import common
from reportlab.graphics.barcode import qr
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Drawing
import string
import os
import imp
from reportlab.lib import colors


canv = canvas.Canvas('Output.pdf')


styles = getSampleStyleSheet()
parastyle = ParagraphStyle(name='Justify', alignment=TA_JUSTIFY)
parastyle.leading = 12
parastyle.fontSize = 11
styles.add(parastyle)

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."

inch = INCH = 72
cm = CM = inch/2.54
mm = MM = cm/10


x=10*mm
y=240*mm
width=190*mm
height=10*mm

canv.saveState()
canv.translate(x,y)
canv.rotate(0)
canv.translate(-x,-y)

p = Paragraph(drawText, styles["Justify"])

p.wrapOn(canv, width, height)
p.drawOn(canv, x, y)

canv.showPage()
canv.save()

这是当前的输出 Output

我需要获取段落中打印的行数。 在我的示例中,我必须得到 11。

如果我改变字体和字体大小,我必须得到相应的值。

【问题讨论】:

    标签: python reportlab paragraph


    【解决方案1】:

    我认为目前在 Reportlab 中根本不可能,因为 flowable 并不直接“了解”内容。另见this exchange on the reportlab mailing list

    【讨论】:

      【解决方案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))
      

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

      【讨论】:

        【解决方案3】:

        在您调用Paragraph.wrapParagraph.wrapOn 之后,您有一个名为blPara 的属性可用,它有一个名为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)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-06-14
          • 2022-01-02
          • 1970-01-01
          • 1970-01-01
          • 2021-11-09
          • 1970-01-01
          • 2016-10-08
          • 2011-05-15
          相关资源
          最近更新 更多