如何使用 pycairo 创建字母间距属性?

Posted

技术标签:

【中文标题】如何使用 pycairo 创建字母间距属性?【英文标题】:How to create a letter spacing attribute with pycairo? 【发布时间】:2019-08-27 05:38:19 【问题描述】:

我正在使用 Pango + Cairo(通过 GObject)通过 python3.7 呈现文本,并希望通过创建一个属性并将该属性附加到我的 pango 布局来设置 字母间距

在 pango 的 gnome 文档中,我可以看到应该有一个名为 pango_attr_letter_spacing_new 的函数(从 v1.6 开始)。但是,如果我运行 Pango.attr_letter_spacing_new,我会收到错误:

AttributeError: 'gi.repository.Pango' object has no attribute 'attr_letter_spacing_new'

这感觉有点奇怪,因为我可以使用 pango_attr_type_get_name,它应该只在 v1.22 之后才可用。

我有一个解决方法,将markup 与<span letter_spacing="1234"> 一起使用,但我不想走这条路。

最小的“工作”示例

# pip install pycairo==1.18.0 pygobject==3.32.0

import cairo
import gi
gi.require_version('Pango', '1.0')
gi.require_version('PangoCairo', '1.0')
from gi.repository import Pango, PangoCairo

width, height = 328, 48

surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
context = cairo.Context(surface)
layout = PangoCairo.create_layout(context)

font_desc = Pango.font_description_from_string('Sans, 40px')
layout.set_font_description(font_desc)

# What I can do
layout.set_markup(f'<span letter_spacing="1024 * 10">Hello World</span>')

# What I would like to do
if False:
    letter_spacing_attr = Pango.attr_letter_spacing_new(1024 * 10)

    attr_list = Pango.AttrList()
    attr_list.insert(letter_spacing_attr)
    layout.set_attributes(attr_list)

    layout.set_text('Hello World')

PangoCairo.show_layout(context, layout)

with open('help-me.png', 'wb') as image_file:
    surface.write_to_png(image_file)

手动创建 LetterSpacing 属性

我已经能够找到枚举值Pango.AttrType.LETTER_SPACING,这让我可以做这样的事情:

c = Pango.AttrClass()
c.type = Pango.AttrType.LETTER_SPACING
a = Pango.Attribute()
a.init(c)

但是,我一直无法找到设置它的值的方法,这让我认为这是错误的处理方式:|

将其插入Pango.AttrList,出现错误(并不奇怪),并在我下次使用 Pango 执行某些操作时使 python 进程出现段错误:

** (process:17183): WARNING **: 12:00:56.985: (gi/pygi-struct-marshal.c:287):pygi_arg_struct_from_py_marshal: runtime check failed: (g_type_is_a (g_type, G_TYPE_VARIANT) || !is_pointer || transfer == GI_TRANSFER_NOTHING)

其他线索

.. 可悲的是无处可寻:(

pygtk listing a function pango.AttrLetterSpacing Pango.AttrLetterSpacing => 'gi.repository.Pango' object has no attribute 'AttrLetterSpacing' Pango.Attrbute.LetterSpacing => type object 'Attribute' has no attribute 'LetterSpacing' Vala 的 pango 包的文档(它似乎也使用 GObject),也显示了attr_letter_spacing_new function——这并没有太大帮助,但建议该函数应该通过 GObject 提供,虽然我没试过。

【问题讨论】:

查看this page 的 pygobject 文档,似乎 attr_letter_spacing_new 函数在没有 python 等效项的情况下不可用。这与this question 中所说的相匹配,因为它在 pygtk -> pygobject 转换中丢失了。 一些可能会导致解决方案的进一步研究。 pitivi 视频编辑器项目使用 PyGObject。他们显然可以解决有缺陷的Pango.AttrList 类,如here 所示。 @CodeSurgeon 这很有趣,尽管他们几乎完全重新实现了它(“FIXME Fix Pango 所以我们不需要那个肮脏的重新实现 Pango.AttrList”)。原始问题中建议的&lt;span&gt; 解决方法看起来更干净(尤其是在您只需要此属性而不是全部属性的情况下)。 @MichalČihař 当然,只是想展示那里的内容。最好使用“跨度”解决方法。如果您想创建一个将这些数字传递到跨度中的函数,则始终可以使用 .format() 语法。 使用标记有一个很大的问题,就是你需要确保输入被转义。在我们的例子中,输入直接来自用户,所以这就是我想要另一种方法的原因:) 【参考方案1】:

看起来这个问题已经解决了,使用 pycairo 1.20.0 和 PyGObject 3.40.1:

import cairo
import gi
gi.require_version('Pango', '1.0')
gi.require_version('PangoCairo', '1.0')
from gi.repository import Pango, PangoCairo

width, height = 328, 48

surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
context = cairo.Context(surface)
layout = PangoCairo.create_layout(context)

font_desc = Pango.font_description_from_string('Sans, 40px')
layout.set_font_description(font_desc)

letter_spacing_attr = Pango.attr_letter_spacing_new(1024 * 10)

attr_list = Pango.AttrList()
attr_list.insert(letter_spacing_attr)
layout.set_attributes(attr_list)

layout.set_text('Hello World')

PangoCairo.show_layout(context, layout)

with open('help-me.png', 'wb') as image_file:
    surface.write_to_png(image_file)

【讨论】:

确认工作正常(pycairo 1.20.1,PyGObject 3.42.0)

以上是关于如何使用 pycairo 创建字母间距属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 Textview 中的字母间距?

如何在android的提示文本中设置字母间距

如何在 Swift 中更改字母间距?

如何在视图之间创建具有可变间距的 UIStackView?

如何以 css px 或 rem 计算 Photoshop 字母间距?

如何对 QComboBox 中的文本执行字母间距?