Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Changes in SVG backend to improve compatibility with Affinity designer #28504

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
95 changes: 43 additions & 52 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -1066,12 +1066,13 @@
self._update_glyph_map_defs(glyph_map_new)

for glyph_id, xposition, yposition, scale in glyph_info:
attrib = {'xlink:href': f'#{glyph_id}'}
if xposition != 0.0:
attrib['x'] = _short_float_fmt(xposition)
if yposition != 0.0:
attrib['y'] = _short_float_fmt(yposition)
writer.element('use', attrib=attrib)
writer.element(
'use',
transform=_generate_transform([
('translate', (xposition, yposition)),
('scale', (scale,)),
]),
attrib={'xlink:href': f'#{glyph_id}'})

else:
if ismath == "TeX":
Expand Down Expand Up @@ -1109,25 +1110,26 @@
writer = self.writer

color = rgb2hex(gc.get_rgb())
style = {}
font_style = {}
color_style = {}
if color != '#000000':
style['fill'] = color
color_style['fill'] = color

Check warning on line 1116 in lib/matplotlib/backends/backend_svg.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_svg.py#L1116

Added line #L1116 was not covered by tests

alpha = gc.get_alpha() if gc.get_forced_alpha() else gc.get_rgb()[3]
if alpha != 1:
style['opacity'] = _short_float_fmt(alpha)
color_style['opacity'] = _short_float_fmt(alpha)

if not ismath:
attrib = {}

font_parts = []
# Separate font style in their separate attributes
if prop.get_style() != 'normal':
font_parts.append(prop.get_style())
font_style['font-style'] = prop.get_style()

Check warning on line 1127 in lib/matplotlib/backends/backend_svg.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_svg.py#L1127

Added line #L1127 was not covered by tests
if prop.get_variant() != 'normal':
font_parts.append(prop.get_variant())
font_style['font-variant'] = prop.get_variant()

Check warning on line 1129 in lib/matplotlib/backends/backend_svg.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_svg.py#L1129

Added line #L1129 was not covered by tests
weight = fm.weight_dict[prop.get_weight()]
if weight != 400:
font_parts.append(f'{weight}')
font_style['font-weight'] = f'{weight}'

def _normalize_sans(name):
return 'sans-serif' if name in ['sans', 'sans serif'] else name
Expand All @@ -1150,15 +1152,15 @@
for entry in prop.get_family()
for name in _expand_family_entry(entry)]

font_parts.extend([
f'{_short_float_fmt(prop.get_size())}px',
# ensure expansion, quoting, and dedupe of font names
", ".join(dict.fromkeys(_get_all_quoted_names(prop)))
])
style['font'] = ' '.join(font_parts)
font_style['font-size'] = f'{_short_float_fmt(prop.get_size())}px'
# ensure expansion, quoting, and dedupe of font names
font_style['font-family'] = ", ".join(
dict.fromkeys(_get_all_quoted_names(prop))
)

if prop.get_stretch() != 'normal':
style['font-stretch'] = prop.get_stretch()
attrib['style'] = _generate_css(style)
font_style['font-stretch'] = prop.get_stretch()
attrib['style'] = _generate_css({**font_style, **color_style})

if mtext and (angle == 0 or mtext.get_rotation_mode() == "anchor"):
# If text anchoring can be supported, get the original
Expand All @@ -1180,11 +1182,11 @@

ha_mpl_to_svg = {'left': 'start', 'right': 'end',
'center': 'middle'}
style['text-anchor'] = ha_mpl_to_svg[mtext.get_ha()]
font_style['text-anchor'] = ha_mpl_to_svg[mtext.get_ha()]

attrib['x'] = _short_float_fmt(ax)
attrib['y'] = _short_float_fmt(ay)
attrib['style'] = _generate_css(style)
attrib['style'] = _generate_css({**font_style, **color_style})
attrib['transform'] = _generate_transform([
("rotate", (-angle, ax, ay))])

Expand All @@ -1204,7 +1206,7 @@
# Apply attributes to 'g', not 'text', because we likely have some
# rectangles as well with the same style and transformation.
writer.start('g',
style=_generate_css(style),
style=_generate_css({**font_style, **color_style}),
transform=_generate_transform([
('translate', (x, y)),
('rotate', (-angle,))]),
Expand All @@ -1216,43 +1218,32 @@
spans = {}
for font, fontsize, thetext, new_x, new_y in glyphs:
entry = fm.ttfFontProperty(font)
font_parts = []
font_style = {}
# Separate font style in its separate attributes
if entry.style != 'normal':
font_parts.append(entry.style)
font_style['font-style'] = entry.style
if entry.variant != 'normal':
font_parts.append(entry.variant)
font_style['font-variant'] = entry.variant

Check warning on line 1226 in lib/matplotlib/backends/backend_svg.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_svg.py#L1226

Added line #L1226 was not covered by tests
if entry.weight != 400:
font_parts.append(f'{entry.weight}')
font_parts.extend([
f'{_short_float_fmt(fontsize)}px',
f'{entry.name!r}', # ensure quoting
])
style = {'font': ' '.join(font_parts)}
font_style['font-weight'] = f'{entry.weight}'
font_style['font-size'] = f'{_short_float_fmt(fontsize)}px'
font_style['font-family'] = f'{entry.name!r}' # ensure quoting
if entry.stretch != 'normal':
style['font-stretch'] = entry.stretch
style = _generate_css(style)
font_style['font-stretch'] = entry.stretch

Check warning on line 1232 in lib/matplotlib/backends/backend_svg.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/backends/backend_svg.py#L1232

Added line #L1232 was not covered by tests
style = _generate_css({**font_style, **color_style})
if thetext == 32:
thetext = 0xa0 # non-breaking space
spans.setdefault(style, []).append((new_x, -new_y, thetext))

for style, chars in spans.items():
chars.sort()

if len({y for x, y, t in chars}) == 1: # Are all y's the same?
ys = str(chars[0][1])
else:
ys = ' '.join(str(c[1]) for c in chars)

attrib = {
'style': style,
'x': ' '.join(_short_float_fmt(c[0]) for c in chars),
'y': ys
}

writer.element(
'tspan',
''.join(chr(c[2]) for c in chars),
attrib=attrib)
chars.sort() # Sort by increasing x position
for x, y, t in chars: # Output one tspan for each character
writer.element(
'tspan',
chr(t),
x=_short_float_fmt(x),
y=_short_float_fmt(y),
style=style)

writer.end('text')

Expand Down
11 changes: 10 additions & 1 deletion lib/matplotlib/testing/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import sys
from tempfile import TemporaryDirectory, TemporaryFile
import weakref
import re

import numpy as np
from PIL import Image
Expand Down Expand Up @@ -305,7 +306,15 @@ def convert(filename, cache):
# re-generate any SVG test files using this mode, or else such tests will
# fail to use the converter for the expected images (but will for the
# results), and the tests will fail strangely.
if 'style="font:' in contents:
if re.search(
# searches for attributes :
# style=[font|font-size|font-weight|
# font-family|font-variant|font-style]
# taking care of the possibility of multiple style attributes
# before the font styling (i.e. opacity)
r'style="[^"]*font(|-size|-weight|-family|-variant|-style):',
contents # raw contents of the svg file
):
# for svg.fonttype = none, we explicitly patch the font search
# path so that fonts shipped by Matplotlib are found.
convert = _svg_with_matplotlib_fonts_converter
Expand Down
Loading
Loading