使用svgwrite for python时如何确定文本宽度和高度?

时间:2014-06-21 01:43:42

标签: python svg

我希望提取文本对象的像素大小(svgwrite.Drawing.Text),因为它在使用给定样式进行格式化后会显示在文件中。我的字体是固定宽度的(Courier New)。

我需要它的原因是我想要在SVG文件中打印一个字符串,然后在结果文本上映射一些信息:例如我有一个字符串" ABCDEF"外部智者告诉我" BCD"部分应该标记。然后我需要知道有多少像素(单位?)被符号" A"和符号" BCD"在两个维度中,然后绘制一个彩色矩形,或透明框架,或严格在" BCD"部分。

所以我有以下代码,我希望使用" w = text1.width "提取宽度,但它没有这种方式。提前感谢您尝试回答我的问题。

import svgwrite
my_svg = svgwrite.Drawing(filename = "dasha.svg", size = ("800px", "600px"))
text_style = "font-size:%ipx; font-family:%s" % (12, "Courier New") 
text1 = my_svg.text("HELLO WORLD", insert=(0, 0), fill="black", style=text_style)
my_svg.add(text1)
my_svg.save()

UPD1 [22.06.2014] :我目前使用的中间解决方案是在Inkscape中手动测量具有特定字体和大小的字母的高度和宽度。我尽我所能,但我不确定这些值是否完美,现在我无法改变程序中的字体大小。

4 个答案:

答案 0 :(得分:4)

我想用特定字体确定svgwrite中文本的宽度。 我最终使用了http://blog.mathieu-leplatre.info/text-extents-with-python-cairo.html中的以下解决方案:

def textwidth(text, fontsize=14):
    try:
        import cairo
    except Exception, e:
        return len(str) * fontsize
    surface = cairo.SVGSurface('undefined.svg', 1280, 200)
    cr = cairo.Context(surface)
    cr.select_font_face('Arial', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
    cr.set_font_size(fontsize)
    xbearing, ybearing, width, height, xadvance, yadvance = cr.text_extents(text)
    return width

它引入了cairo作为依赖,但它是迄今为止我发现的最清晰的独立于平台的解决方案。

答案 1 :(得分:1)

我有同样的问题,但我有一个可变宽度的字体。我通过获取我想要的文本元素(正确的字体和内容),将其写入svg文件,并使用安装在我的PC上的Inkscape来将绘图转换为临时png文件来解决它。然后我回读了png文件的大小(从标题中提取),删除了临时svg和png文件,并使用结果将文本放在我想要的位置和周围的元素。

我发现渲染到绘图,使用90的DPI似乎给了我所需的确切数字,或者整个svgwrite中使用的原生数字。 -D是要使用的标志,以便只渲染可绘制元素,即文本。

os.cmd(/cygdrive/c/Program\ Files\ \(x86\)/Inkscape/inkscape.exe -f work_temp.svg -e work_temp.png -d 90 -D)

我使用这些函数来提取png数字,在link找到,注意我的python3略有修正(仍然在python2中工作)

def is_png(data):
    return (data[:8] == b'\x89PNG\r\n\x1a\n'and (data[12:16] == b'IHDR'))

def get_image_info(data):
    if is_png(data):
        w, h = struct.unpack('>LL', data[16:24])
        width = int(w)
        height = int(h)
    else:
        raise Exception('not a png image')
    return width, height

if __name__ == '__main__':
    with open('foo.png', 'rb') as f:
        data = f.read()

    print is_png(data)
    print get_image_info(data)

它很笨重,但它有效

答案 2 :(得分:0)

我最终使用了Tkinter:

try:
    # for Python2
    import Tkinter
except ImportError:
    # for Python3
    import tkinter as Tkinter

try:
    import tkFont
except ImportError:
    import tkinter.font as tkFont

def get_text_metrics(family, size, text):
    # initialize Tk so that font metrics will work
    tk_root = Tkinter.Tk()
    font = None
    key = (family, size)
    font = tkFont.Font(family=family, size=size)
    assert font is not None
    (w, h) = (font.measure(text), font.metrics('linespace'))
    return (w, h)

答案 3 :(得分:-1)

我不是svg的专家,但我的理解是,很难确定svg中的字符和文本宽度。这意味着svgwrite也无法做到这一点。我所做的是为字符选择一个固定的宽度,并从前一个字符的开头分别创建一个固定宽度的每个字符。您也可以考虑使用text_anchor ='middle'来对齐字符串,即每个字符。对于以点为中心的字符,可以创建一个框以使该点居中。

另见http://www.w3.org/TR/SVG/text.html 其中说“在很多情况下,从字符到字形的映射算法都是系统相关的,导致在不同的用户环境中查看文本的呈现可能(通常略有不同)。如果SVG内容的作者需要精确选择字体和字形,然后建议必要的字体(可能是子集,只包括给定文档所需的字形)可用作SVG内容中嵌入的SVG字体或WebFonts([CSS2],第15.1节) )发布在与SVG内容相同的Web位置。“