如何在 svgwrite 中实现文本换行? 更新:渲染文本的理由:

问题描述

我在 python 中使用 svgwrite 根据我的 Tensorflow 模型生成输出输出模拟手写文本。我当前的设置需要一个字符串数组来表示换行符,但是生成的文本大小不一致,有时会在行中的最后一个单词之后呈现尴尬的间距,例如

this

是否可以向单个长行添加文本换行,当当前行达到给定的最大宽度时自动添加换行符? Google 搜索将我带到 svgwrite 页面并建议使用 TextArea,但给出的示例是 HTML。

    def _draw(self,strokes,lines,filename,stroke_colors=None,\
          stroke_widths=None,background_color='white'):

    lines = [
        "Lorem ipsum dolor sit amet,consectetur adipiscing elit,","sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.","Ut enim ad minim veniam,quis nostrud exercitation ullamco laboris","nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in","reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
    ]

    stroke_colors = stroke_colors or ['black']*len(lines)
    stroke_widths = stroke_widths or [2]*len(lines)

    line_height = 35
    view_width = 152.4
    view_height = 101.6

    dwg = svgwrite.Drawing(filename=filename)
    dwg.viewBox(width=view_width,height=view_height)
    dwg.add(dwg.rect(insert=(0,0),size=('153mm','102mm'),fill=background_color))

    for i in range(3):
            
        
        initial_coord = np.array([30,-((i*450)+25)])
        strokesc = self._sample(lines,[1 for i in lines],[7 for i in lines]);
        
        for offsets,line,color,width in zip(strokesc,stroke_colors,stroke_widths):

            if not line:
                initial_coord[1] -= line_height
                continue
            offsets[:,:2] *= random.randint(150,190)/100
            strokesc = drawing.offsets_to_coords(offsets)
            strokesc = drawing.denoise(strokesc)
            strokesc[:,:2] = drawing.align(strokesc[:,:2])

            strokesc[:,1] *= -1
            strokesc[:,:2] -= strokesc[:,:2].min() + initial_coord

            prev_eos = 1.0
            p = "M{},{} ".format(0,0)
            for x,y,eos in zip(*strokesc.T):
                p += '{}{},{} '.format('M' if prev_eos == 1.0 else 'L',x,y)
                prev_eos = eos
            path = svgwrite.path.Path(p)
            path = path.stroke(color=color,width=width,linecap='round').fill("none")
            dwg.add(path)

            initial_coord[1] -= line_height

    dwg.save()

这是我当前在 python 中的解决方案,它输出上面的例子

解决方法

您可以尝试直接处理文本:

my_text = sum(lines)
nb_lines = len(lines)


nb_words_per_line = len(my_text.split()) // nb_lines

new_lines = []
cmpt = 0
tmp = ""
for i,word in enumerate(my_text.split()):
    
    if cmpt%nb_words_per_line == 0:
        new_lines.append(tmp)
        tmp = ""
    tmp += word + " "

if tmp:
    new_lines.append(tmp)
    

然后您可以像之前使用的 new_lines 一样使用 lines

,

所以您只想用预定义的最大数量包装文本。字符?
我想 python 的原生 textwrap 就是你要搜索的

textwrap 模块提供了一些方便的功能,以及完成所有工作的类 TextWrapper。如果只是对一两个文本字符串进行换行或填充,那么方便的功能应该足够了;否则,您应该使用 TextWrapper 实例以提高效率。

import textwrap

lines = [
    "Lorem ipsum dolor sit amet,consectetur adipiscing elit,","sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.","Ut enim ad minim veniam,quis nostrud exercitation ullamco laboris","nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in","reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
]

textwrap.wrap(" ".join(lines),40)

>>> Out:
>>> ['Lorem ipsum dolor sit amet,consectetur',>>> 'adipiscing elit,sed do eiusmod tempor',>>> 'incididunt ut labore et dolore magna',>>> 'aliqua. Ut enim ad minim veniam,quis',>>> 'nostrud exercitation ullamco laboris',>>> 'nisi ut aliquip ex ea commodo consequat.',>>> 'Duis aute irure dolor in reprehenderit',>>> 'in voluptate velit esse cillum dolore eu',>>> 'fugiat nulla pariatur.']

或者如果您直接想用换行符连接结果字符串列表:

textwrap.fill(" ".join(lines),40)
>>> Out:
>>> 'Lorem ipsum dolor sit amet,consectetur\nadipiscing elit,sed do eiusmod tempor\nincididunt ut labore et dolore magna\naliqua. Ut enim ad minim veniam,quis\nnostrud exercitation ullamco laboris\nnisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit\nin voluptate velit esse cillum dolore eu\nfugiat nulla pariatur.'

更新:渲染文本的理由:

渲染文本的“实际”对齐是通过指定“textLength”属性来实现的(有关更多详细信息和选项,请参阅 herehere)。

import sys
import svgwrite

import textwrap

lines = [
    "Lorem ipsum dolor sit amet,"reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
]

# wrap text to max. 40 characters
usetext = textwrap.wrap(" ".join(lines),40)

filename = sys.argv[0].rstrip('.py')

def create_svg(name):
    svg_width = 500
    svg_height = 300

    font_size = 20
    dwg = svgwrite.Drawing(name,(svg_width,svg_height),debug=True)
    # background will be white.
    dwg.add(dwg.rect(insert=(0,0),size=('100%','100%'),fill='white'))
    
    for i,line in enumerate(usetext):
        dwg.add(dwg.text(line,insert=(0,font_size * (i + 4)),font_family="serif",font_size=font_size,fill='black',textLength=svg_width),)
    
    dwg.save()

if __name__ == '__main__':
    create_svg(filename + '.svg')

enter image description here