简体   繁体   中英

How to implement text wrapping in svgwrite?

I'm using svgwrite in python to generate output based off my Tensorflow model to output simulated handwritten text. My current setup requires an array of strings to represent line breaks however the generated text size isn't consistent and sometimes renders awkward spacing after the last word in the line such as这

Is it possible to add text-wrapping to a single long line that would automatically add line breaks when the current line reaches the max width given? A Google Search brought me to the svgwrite page and suggested to use TextArea but the examples given are 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()

This is my current solution in python which outputs the example above

You could try working directly on the text :

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)
    

You can then use new_lines as you used lines before.

so you simply want to wrap a text with a predefined number of max. characters?
I guess python's native textwrap is what you're searching for

The textwrap module provides some convenience functions, as well as TextWrapper, the class that does all the work. If you're just wrapping or filling one or two text strings, the convenience functions should be good enough; otherwise, you should use an instance of TextWrapper for efficiency.

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

or if you directly want to join the resulting list of strings with newlines:

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

update: justification of rendered text:

the "actual" justification of the rendered text is achieved by specifying the "textLength" property (see here and here for more details and options).

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')

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM