File: test_523_text_size.py

package info (click to toggle)
ezdxf 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 104,528 kB
  • sloc: python: 182,341; makefile: 116; lisp: 20; ansic: 4
file content (171 lines) | stat: -rw-r--r-- 5,336 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#  Copyright (c) 2021-2025, Manfred Moitzi
#  License: MIT License

import pytest

import ezdxf
from ezdxf.layouts import VirtualLayout
from ezdxf.tools.text_size import (
    text_size,
    mtext_size,
    estimate_mtext_extents,
)
from ezdxf.tools.text import (
    set_estimation_safety_factor,
    reset_estimation_safety_factor,
)
from ezdxf.tools.text_layout import leading


@pytest.fixture
def msp():
    yield VirtualLayout()


H3W1 = {"height": 3.0, "width": 1.0}
H2W2 = {"height": 2.0, "width": 2.0}


def test_text_size_of_an_empty_string(msp):
    """The text_size() function does not measure the actual height of a char,
    it always returns the font measurement cap-height for text height and
    cap-height + descender for the total text height.
    """
    text = msp.add_text("", dxfattribs=H3W1)
    size = text_size(text)
    assert size.width == 0.0
    assert size.cap_height == 3.0
    assert size.total_height > 3.3  # assuming the descender factor is > 0.1


def test_text_width_of_a_single_char(msp):
    """The "MonospaceFont" font has a char width of cap-height x width factor."""
    text = msp.add_text("X", dxfattribs=H3W1)
    size = text_size(text)
    assert size.width == 3.0, "char width should be equal to cap height"


@pytest.mark.parametrize("s", ["ABC", ".,!", "   "])
def test_text_width_of_a_string(msp, s):
    text = msp.add_text(s, dxfattribs=H3W1)
    size = text_size(text)
    assert size.width == len(s) * size.cap_height


@pytest.mark.parametrize("s", ["ABC", ".,!", "   "])
def test_text_width_of_a_string_for_width_factor_2(msp, s):
    text = msp.add_text(s, dxfattribs=H2W2)
    size = text_size(text)
    assert size.width == len(s) * size.cap_height * 2.0


@pytest.mark.parametrize(
    "s",
    [
        "ABC\n",  # remove line ending
        "ABC\r",  # remove line ending
        "AB^I",  # parse caret notation "^I" -> "\t" (tabulator)
        "AB%%d",  # parse special chars "%%d" -> "°"
    ],
)
def test_measurement_of_plain_text(msp, s):
    text = msp.add_text(s, dxfattribs=H3W1)
    size = text_size(text)
    assert size.width == 3.0 * size.cap_height


def test_support_for_text_size():
    test_string = "TestString"
    doc = ezdxf.new()
    doc.styles.add("OpenSans", font="OpenSans-Regular.ttf")
    text = doc.modelspace().add_text(
        test_string,
        dxfattribs={
            "style": "OpenSans",
            "height": 2.0,
        },
    )
    length = len(test_string)
    size = text_size(text)
    # Do not check exact measurements!
    assert length * 1.0 < size.width < length * 2.0
    assert 1.95 < size.cap_height < 2.05
    assert size.total_height > size.cap_height


def test_mtext_size_of_an_empty_string(msp):
    mtext = msp.add_mtext("", dxfattribs={"char_height": 1.0})
    size = mtext_size(mtext)
    assert size.total_width == 0.0
    assert size.total_height == 0.0
    assert size.column_width == 0.0
    assert size.gutter_width == 0.0
    assert size.column_count == 1
    assert size.column_heights == (0.0,)


def test_mtext_size_of_a_single_char(msp):
    set_estimation_safety_factor(1.0)
    # Matplotlib support disabled and using MonospaceFont()
    mtext = msp.add_mtext("X", dxfattribs={"char_height": 2.0})
    size = mtext_size(mtext)
    assert size.total_height == 2.0
    assert size.total_width == pytest.approx(1.8794373744139317)
    assert size.column_width == pytest.approx(1.8794373744139317)
    assert size.gutter_width == 0.0
    assert size.column_count == 1
    reset_estimation_safety_factor()


def test_mtext_size_of_a_string(msp):
    set_estimation_safety_factor(1.0)
    # Matplotlib support disabled and using MonospaceFont()
    mtext = msp.add_mtext("XXX", dxfattribs={"char_height": 2.0})
    size = mtext_size(mtext)
    assert size.total_height == 2.0
    assert size.total_width == pytest.approx(5.6383121232417945)
    assert size.column_width == size.total_width
    assert size.gutter_width == 0.0
    assert size.column_count == 1
    reset_estimation_safety_factor()


def test_estimate_mtext_extents(msp):
    set_estimation_safety_factor(1.0)
    # Matplotlib support disabled and using MonospaceFont()
    mtext = msp.add_mtext(
        "XXXXXXXXXXXX\nYYYY\nZ",  # 5 lines!
        dxfattribs={
            "char_height": 2.0,
            "width": 8.0,
        },
    )
    width, height = estimate_mtext_extents(mtext)
    assert height == pytest.approx(15.336)  # 5 lines!
    assert width == 8.0
    reset_estimation_safety_factor()


@pytest.mark.parametrize(
    "cap_height, expected", [(2.0, 6.703281982585398), (3.0, 10.054922973878098)]
)
def test_mtext_size_of_2_lines(cap_height, expected, msp):
    set_estimation_safety_factor(1.0)
    # Matplotlib support disabled and using MonospaceFont()
    mtext = msp.add_mtext(
        "XXX\nYYYY",
        dxfattribs={
            "char_height": cap_height,
            "line_spacing_factor": 1.0,
        },
    )
    size = mtext_size(mtext)
    expected_total_height = leading(cap_height, line_spacing=1.0) + cap_height
    assert size.total_height == pytest.approx(expected_total_height)
    assert size.total_width == pytest.approx(expected), "expected width of 2nd line"
    assert size.column_width == size.total_width
    reset_estimation_safety_factor()


if __name__ == "__main__":
    pytest.main([__file__])