ink_extents()和text_extents()在cairo RecordingSurface中产生奇怪的结果

2024-05-01 16:25:47 发布

您现在位置:Python中文网/ 问答频道 /正文

以下是在ArchLinux上使用Python 3.9.1、Python cairo 1.20.0和cairo 1.17.4进行的测试

我试图使用cairo RecordingSurface绘制一个包含初始未知大小文本的图形。稍后应在PDFSurface上进行渲染

第一个问题:当我的RecordingSurface仅包含文本时,ink_extents()返回的大小似乎有点错误:

#!/usr/bin/env python
import math
import cairo

text = "Ay"

with cairo.RecordingSurface(cairo.Content.COLOR_ALPHA, None) as recsrf:
    ctx = cairo.Context(recsrf)

    ctx.select_font_face("Arial", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL);
    ctx.show_text(text)

    ext = recsrf.ink_extents()
    print(ext)
    x0, y0, recwidth, recheight = recsrf.ink_extents()

    with cairo.PDFSurface("RecordingSurface.pdf", recwidth, recheight) as pdfsrf:
        ctx = cairo.Context(pdfsrf)
        ctx.set_source_surface(recsrf, -x0, -y0)
        ctx.paint()

产生this image。很明显,字母的某些部分被切掉了,而左边的空间太大了。输出ink_extents()的结果是:

(-1.0, -7.0, 13.0, 9.0)

这看起来像是舍入丢失了细节

接下来,我尝试在RecordingSurface和直接在PDFSurface中使用text_extents在文本周围绘制一个矩形:

#!/usr/bin/env python
import math
import cairo

text = "Ay"

with cairo.RecordingSurface(cairo.Content.COLOR_ALPHA, None) as recsrf:
    ctx = cairo.Context(recsrf)

    ctx.select_font_face("Arial", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL);
    ctx.show_text(text)

    ext = ctx.text_extents(text)
    print(ext)
    x_bearing, y_bearing, width, height, x_advance, y_advance = ext

    ctx.set_source_rgba(1.0, 0.0, 0.0, 0.5)
    ctx.set_line_width(0.01)
    ctx.rectangle(x_bearing, y_bearing, width, height)
    ctx.stroke()

    ext2 = recsrf.ink_extents()
    print(ext2)
    x0, y0, recwidth, recheight = ext2

    with cairo.PDFSurface("RecordingSurface.pdf", recwidth, recheight) as pdfsrf:
        ctx = cairo.Context(pdfsrf)
        ctx.set_source_surface(recsrf, -x0, -y0)
        ctx.paint()

with cairo.PDFSurface("PDFSurface.pdf", 15, 15) as pdfsrf2:
    ctx2 = cairo.Context(pdfsrf2)

    ctx2.move_to(1, 10)
    ctx2.select_font_face("Arial", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL);
    ctx2.show_text(text)

    ext3 = ctx2.text_extents(text)
    print(ext3)
    x_bearing2, y_bearing2, width2, height2, x_advance2, y_advance2 = ext3

    ctx2.set_source_rgba(1.0, 0.0, 0.0, 0.5)
    ctx2.set_line_width(0.01)
    ctx2.rectangle(1 + x_bearing2, 10 + y_bearing2, width2, height2)
    ctx2.stroke()

image for the PDFSurface看起来不错,而image for the RecordingSurface的矩形位置错误(但看起来与上面ink_extents()的裁剪一致)。此外,第二幅图像中的白色边框也是意外的

查看输出,RecordingSurface中的text_extents()看起来“几乎是圆形的”,但存在十进制/二进制分数转换错误(?)

cairo.TextExtents(x_bearing=-1.0, y_bearing=-7.000000000000001, width=13.0, height=9.000000000000002, x_advance=12.0, y_advance=0.0)

ink_extents()再次返回完全四舍五入的数字:

(-2.0, -8.0, 15.0, 11.0)

PDFSurface中只有text_extents()返回精确的结果:

cairo.TextExtents(x_bearing=-0.0146484375, y_bearing=-7.158203125, width=11.5966796875, height=9.2626953125, x_advance=11.669921875, y_advance=0.0)

最后一个问题是:当我简单地交换两个代码块时,RecordingSurface上的结果仍然是错误的,但方式不同:

#!/usr/bin/env python
import math
import cairo

text = "Ay"

with cairo.PDFSurface("PDFSurface.pdf", 15, 15) as pdfsrf2:
    ctx2 = cairo.Context(pdfsrf2)

    ctx2.move_to(1, 10)
    ctx2.select_font_face("Arial", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL);
    ctx2.show_text(text)

    ext3 = ctx2.text_extents(text)
    print(ext3)
    x_bearing2, y_bearing2, width2, height2, x_advance2, y_advance2 = ext3

    ctx2.set_source_rgba(1.0, 0.0, 0.0, 0.5)
    ctx2.set_line_width(0.01)
    ctx2.rectangle(1 + x_bearing2, 10 + y_bearing2, width2, height2)
    ctx2.stroke()

with cairo.RecordingSurface(cairo.Content.COLOR_ALPHA, None) as recsrf:
    ctx = cairo.Context(recsrf)

    ctx.select_font_face("Arial", cairo.FontSlant.NORMAL, cairo.FontWeight.NORMAL);
    ctx.show_text(text)

    ext = ctx.text_extents(text)
    print(ext)
    x_bearing, y_bearing, width, height, x_advance, y_advance = ext

    ctx.set_source_rgba(1.0, 0.0, 0.0, 0.5)
    ctx.set_line_width(0.01)
    ctx.rectangle(x_bearing, y_bearing, width, height)
    ctx.stroke()

    ext2 = recsrf.ink_extents()
    print(ext2)
    x0, y0, recwidth, recheight = ext2

    with cairo.PDFSurface("RecordingSurface.pdf", recwidth, recheight) as pdfsrf:
        ctx = cairo.Context(pdfsrf)
        ctx.set_source_surface(recsrf, -x0, -y0)
        ctx.paint()

现在,image from the RecordingSurface的帧太大而不是太小,取整后的数字看起来不同:

cairo.TextExtents(x_bearing=-0.0146484375, y_bearing=-7.158203125, width=11.5966796875, height=9.2626953125, x_advance=11.669921875, y_advance=0.0)
cairo.TextExtents(x_bearing=-1.0, y_bearing=-8.0, width=13.0, height=11.0, x_advance=12.0, y_advance=0.0)
(-2.0, -9.0, 15.0, 13.0)

这是一个bug,还是该机制在RecordingSurface上根本不可靠


Tags: textwithwidthcairoctxnormalinkset