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

在使用svgwrite for python时,如何确定文本宽度和高度?,python,svg,Python,Svg,我想提取文本对象(svgwrite.Drawing.text)的像素大小,它将在使用给定样式格式化后显示在文件中。我的字体是固定宽度(Courier New) 我之所以需要它,是因为我想将一个字符串打印到SVG文件中,然后在生成的文本上映射一些信息:例如,我有一个字符串“ABCDEF”,外部智者告诉我应该标记“BCD”部分。然后我需要知道符号“A”和符号“BCD”在两个维度上覆盖了多少像素(单位?),然后在“BCD”部分下面画一个彩色矩形,或透明框,或其他任何东西 所以我有下面的代码,我希望使用

我想提取文本对象(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中手动测量具有特定字体和大小的字母的高度和宽度。我尽了最大努力,但我不确定这些值是否完美,现在我无法在程序中更改字体大小。

我不是svg专家,但据我所知,在svg中很难确定字符和文本宽度。这意味着svgwrite也无法做到这一点。我所做的是为字符选择一个固定的宽度,并从上一个字符的开头分别创建一个固定的宽度。还可以考虑使用TraceAc锚=“中间”来定中心字符串,即每个字符。当字符位于点的中心时,可以创建一个框,使其也位于该点的中心

另见
这说明“在许多情况下,从字符到字形的映射算法依赖于系统,导致文本的呈现可能(通常是轻微的)在不同的用户环境中查看时会有所不同。如果SVG内容的作者需要精确选择字体和字形,则建议将必要的字体(可能被子集为仅包含给定文档所需的字形)作为SVG内容中嵌入的SVG字体或WebFonts提供([CSS2],第15.1节)发布在与SVG内容相同的Web位置。”

我遇到了完全相同的问题,但我有一个可变宽度字体。我通过使用文本元素(正确的字体和内容)解决了这个问题我想要,将其写入svg文件,并使用电脑上安装的Inkscape将图形渲染为临时png文件。然后,我读回png文件的尺寸(从标题中提取),删除临时svg和png文件,并使用结果将文本放置在我想要的位置和周围的元素

我发现,使用DPI为90的图形渲染似乎可以提供我所需的确切数字,或者svgwrite中使用的本机数字作为一个整体。-D是要使用的标志,以便只渲染可绘制元素,即文本

os.cmd(/cygdrive/c/Program\ Files\ \(x86\)/Inkscape/inkscape.exe -f work_temp.svg -e work_temp.png -d 90 -D)
我使用这些函数来提取png数字,在这里可以找到,注意,我的代码对python3(仍在python2中工作)进行了轻微的修改


它很笨重,但很有效

我想确定svgwrite中特定字体的文本宽度。 我最终使用了以下解决方案:


它以依赖关系的形式引入cairo,但它是迄今为止我发现的最干净的独立于平台的解决方案。

我最终使用了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)

您最好将文本拆分,使BCD位于自己的
中,然后对
进行样式设置,使其看起来突出显示。不需要测量。我想到了这一点,但实际上我需要映射文本上的重叠信息(在本例中,BCD应标记为红色、ABC-蓝色和DEF-绿色).原则上,我仍然可以通过颜色混合来计算适当的颜色,然后独立地给每个字母上色,但如果能以更直接的方式来计算,那就太好了…使用
x
y
文本参数怎么样?如果提供了n的列表,那么这些值代表当前文本位置的新绝对x坐标呈现对应于此元素或其任何子元素中前n个字符中的每个字符的glyph,因此每个字母都有足够大的边距,这可能会起作用。谢谢,这真的节省了我的时间。我黑了一条小Python(3)基于此代码,请在此处找到它:它是否支持不同的字符集?例如ABC和汉字应该是这样的,因为它实际上会将文本渲染到一个不可见的表面。我还没有对它进行彻底测试,所以如果你有任何结果,请与我分享!我发现在选择自定义字体时使用
xadvance
比使用
width
效果更好(没有
cairo.font\u WEIGHT\u BOLD
)。
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
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)