如何在svgwrite中实现文本换行?

5
我正在使用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, lines, 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当前解决方案,可以输出上面的示例。
2个回答

0
你可以尝试直接在文本上进行工作:
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)
    

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


0

所以你只是想用预定义的最大字符数来包装文本吗?
我猜 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”属性来实现渲染文本的“实际”对齐方式(有关更多详细信息和选项,请参阅此处此处)。

import sys
import svgwrite

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

# 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


这种方法的唯一问题是,当单词与绘图函数的其余部分一起处理时,它们的大小会有所不同,这会导致每次线条长度不同。 - TehPirate
是的...但这是文本呈现的一般问题...毕竟,即使每行有相同数量的字符,由于使用的字体不同,渲染后的图像中每行的长度也会不同。 (我不熟悉svgwrite,但也许它有一些选项可以对给定的多行文本进行“对齐”?(例如,拉伸空格以实现相同的行长度) - raphael
@TehPirate 我已经快速查看了 svgwrite 并更新了答案,提供了一个小的工作示例,展示了如何实际获取文本对齐。 - raphael
谢谢@raphael!我很感激你的帮助,我会将其应用到我的项目中。不过这会导致单词被截断到新行上,是吗? - TehPirate
嘿,抱歉没有回复(我在度假)... 我不会期望单词被截断(只有空格会被拉伸以使行符合定义的宽度)。请查看我提供的链接,以获取有关功能的清晰描述。 - raphael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接