Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Switch Tfm metrics to TrueType-compatible API.#29838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
tacaswell merged 2 commits intomatplotlib:mainfromanntzer:texmetrics
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletionsdoc/api/next_api_changes/deprecations/29817-AL.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
``DviFont.widths``
~~~~~~~~~~~~~~~~~~
... is deprecated with no replacement.

Direct access to ``Tfm``'s ``widths``, ``heights``, ``depths`` dicts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
... is deprecated; access a glyph's metrics with `.Tfm.get_metrics` instead.
5 changes: 3 additions & 2 deletionslib/matplotlib/backends/backend_pdf.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -993,8 +993,9 @@ def _embedTeXFont(self, fontinfo):
widthsObject = self.reserveObject('font widths')
tfm = fontinfo.dvifont._tfm
# convert from TeX's 12.20 representation to 1/1000 text space units.
widths = [(1000 * tfm.width.get(char, 0)) >> 20
for char in range(max(tfm.width, default=-1) + 1)]
widths = [(1000 * metrics.tex_width) >> 20
if (metrics := tfm.get_metrics(char)) else 0
for char in range(max(tfm._glyph_metrics, default=-1) + 1)]
self.writeObject(widthsObject, widths)

# Font dictionary
Expand Down
77 changes: 49 additions & 28 deletionslib/matplotlib/dviread.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@
"""

from collections import namedtuple
import dataclasses
import enum
from functools import cache, lru_cache, partial, wraps
import logging
Expand DownExpand Up@@ -604,32 +605,30 @@

def _width_of(self, char):
"""Width of char in dvi units."""
width = self._tfm.width.get(char, None)
ifwidth is not None:
return _mul1220(width,self._scale)
_log.debug('No width for char %d in font %s.', char, self.texname)
return0
metrics = self._tfm.get_metrics(char)
ifmetrics is None:
_log.debug('Nowidth for char %d in font %s.', char,self.texname)
return 0

Check warning on line 611 in lib/matplotlib/dviread.py

View check run for this annotation

Codecov/ codecov/patch

lib/matplotlib/dviread.py#L610-L611

Added lines #L610 - L611 were not covered by tests
return_mul1220(metrics.tex_width, self._scale)

def _height_depth_of(self, char):
"""Height and depth of char in dvi units."""
result = []
for metric, name in ((self._tfm.height, "height"),
(self._tfm.depth, "depth")):
value = metric.get(char, None)
if value is None:
_log.debug('No %s for char %d in font %s',
name, char, self.texname)
result.append(0)
else:
result.append(_mul1220(value, self._scale))
metrics = self._tfm.get_metrics(char)
if metrics is None:
_log.debug('No metrics for char %d in font %s', char, self.texname)
return [0, 0]

Check warning on line 619 in lib/matplotlib/dviread.py

View check run for this annotation

Codecov/ codecov/patch

lib/matplotlib/dviread.py#L618-L619

Added lines #L618 - L619 were not covered by tests
hd = [
_mul1220(metrics.tex_height, self._scale),
_mul1220(metrics.tex_depth, self._scale),
]
# cmsyXX (symbols font) glyph 0 ("minus") has a nonzero descent
# so that TeX aligns equations properly
# (https://tex.stackexchange.com/q/526103/)
# but we actually care about the rasterization depth to align
# the dvipng-generated images.
if re.match(br'^cmsy\d+$', self.texname) and char == 0:
result[-1] = 0
returnresult
hd[-1] = 0
returnhd


class Vf(Dvi):
Expand DownExpand Up@@ -761,6 +760,22 @@
return (num1*num2) >> 20


@dataclasses.dataclass(frozen=True, kw_only=True)
class TexMetrics:
"""
Metrics of a glyph, with TeX semantics.

TeX metrics have different semantics from FreeType metrics: tex_width
corresponds to FreeType's ``advance`` (i.e., including whitespace padding);
tex_height to ``bearingY`` (how much the glyph extends over the baseline);
tex_depth to ``height - bearingY`` (how much the glyph extends under the
baseline, as a positive number).
"""
tex_width: int
tex_height: int
tex_depth: int


class Tfm:
"""
A TeX Font Metric file.
Expand All@@ -778,12 +793,7 @@
design_size : int
Design size of the font (in 12.20 TeX points); unused because it is
overridden by the scale factor specified in the dvi file.
width, height, depth : dict
Dimensions of each character, need to be scaled by the factor
specified in the dvi file. These are dicts because indexing may
not start from 0.
"""
__slots__ = ('checksum', 'design_size', 'width', 'height', 'depth')

def __init__(self, filename):
_log.debug('opening tfm file %s', filename)
Expand All@@ -799,15 +809,26 @@
widths = struct.unpack(f'!{nw}i', file.read(4*nw))
heights = struct.unpack(f'!{nh}i', file.read(4*nh))
depths = struct.unpack(f'!{nd}i', file.read(4*nd))
self.width = {}
self.height = {}
self.depth = {}
self._glyph_metrics = {}
for idx, char in enumerate(range(bc, ec+1)):
byte0 = char_info[4*idx]
byte1 = char_info[4*idx+1]
self.width[char] = widths[byte0]
self.height[char] = heights[byte1 >> 4]
self.depth[char] = depths[byte1 & 0xf]
self._glyph_metrics[char] = TexMetrics(
tex_width=widths[byte0],
tex_height=heights[byte1 >> 4],
tex_depth=depths[byte1 & 0xf],
)

def get_metrics(self, idx):
"""Return a glyph's TexMetrics, or None if unavailable."""
return self._glyph_metrics.get(idx)

width = _api.deprecated("3.11", alternative="get_metrics")(
property(lambda self: {c: m.tex_width for c, m in self._glyph_metrics}))
height = _api.deprecated("3.11", alternative="get_metrics")(
property(lambda self: {c: m.tex_height for c, m in self._glyph_metrics}))
depth = _api.deprecated("3.11", alternative="get_metrics")(
property(lambda self: {c: m.tex_depth for c, m in self._glyph_metrics}))


PsFont = namedtuple('PsFont', 'texname psname effects encoding filename')
Expand Down
19 changes: 16 additions & 3 deletionslib/matplotlib/dviread.pyi
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
import dataclasses
from pathlib import Path
import io
import os
Expand DownExpand Up@@ -68,13 +69,25 @@ class Vf(Dvi):
def __init__(self, filename: str | os.PathLike) -> None: ...
def __getitem__(self, code: int) -> Page: ...

@dataclasses.dataclass(frozen=True, kw_only=True)
class TexMetrics:
tex_width: int
tex_height: int
tex_depth: int
# work around mypy not respecting kw_only=True in stub files
__match_args__ = ()

class Tfm:
checksum: int
design_size: int
width: dict[int, int]
height: dict[int, int]
depth: dict[int, int]
def __init__(self, filename: str | os.PathLike) -> None: ...
def get_metrics(self, idx: int) -> TexMetrics | None: ...
@property
def width(self) -> dict[int, int]: ...
@property
def height(self) -> dict[int, int]: ...
@property
def depth(self) -> dict[int, int]: ...

class PsFont(NamedTuple):
texname: bytes
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp