mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-09-11 20:47:56 +03:00
Improve SVG text-anchor attribute
This commit is contained in:
parent
8bccb7f1d8
commit
1460522596
@ -8,7 +8,8 @@ from xml.etree import ElementTree
|
||||
from cssselect2 import ElementWrapper
|
||||
|
||||
from ..urls import get_url_attribute
|
||||
from .bounding_box import bounding_box, is_valid_bounding_box
|
||||
from .bounding_box import (
|
||||
bounding_box, extend_bounding_box, is_valid_bounding_box)
|
||||
from .css import parse_declarations, parse_stylesheets
|
||||
from .defs import (
|
||||
apply_filters, clip_path, draw_gradient_or_pattern, paint_mask, use)
|
||||
@ -433,6 +434,12 @@ class SVG:
|
||||
display = node.get('display') != 'none'
|
||||
visible = display and (node.get('visibility') != 'hidden')
|
||||
|
||||
# Handle text anchor
|
||||
text_anchor = node.get('text-anchor')
|
||||
if node.tag == 'text' and text_anchor in ('middle', 'end'):
|
||||
group = self.stream.add_group(0, 0, 0, 0) # BBox set after drawing
|
||||
original_stream, self.stream = self.stream, group
|
||||
|
||||
# Draw node
|
||||
if visible and node.tag in TAGS:
|
||||
with suppress(PointError):
|
||||
@ -442,6 +449,27 @@ class SVG:
|
||||
if display and node.tag not in DEF_TYPES:
|
||||
for child in node:
|
||||
self.draw_node(child, font_size, fill_stroke)
|
||||
if node.tag in ('text', 'tspan'):
|
||||
if not is_valid_bounding_box(child.text_bounding_box):
|
||||
continue
|
||||
x1, y1 = child.text_bounding_box[:2]
|
||||
x2 = x1 + child.text_bounding_box[2]
|
||||
y2 = y1 + child.text_bounding_box[3]
|
||||
node.text_bounding_box = extend_bounding_box(
|
||||
node.text_bounding_box, ((x1, y1), (x2, y2)))
|
||||
|
||||
# Handle text anchor
|
||||
if node.tag == 'text' and text_anchor in ('middle', 'end'):
|
||||
group_id = self.stream.id
|
||||
self.stream = original_stream
|
||||
self.stream.push_state()
|
||||
if is_valid_bounding_box(node.text_bounding_box):
|
||||
x, y, width, height = node.text_bounding_box
|
||||
group.extra['BBox'][:] = (x, y, x + width, y + height)
|
||||
x_align = width / 2 if text_anchor == 'middle' else width
|
||||
self.stream.transform(e=-x_align)
|
||||
self.stream.draw_x_object(group_id)
|
||||
self.stream.pop_state()
|
||||
|
||||
# Apply mask
|
||||
mask = self.masks.get(parse_url(node.get('mask')).fragment)
|
||||
|
@ -44,8 +44,6 @@ def text(svg, node, font_size):
|
||||
|
||||
layout, _, _, width, height, _ = split_first_line(
|
||||
node.text, style, svg.context, inf, 0)
|
||||
# TODO: get real values
|
||||
x_bearing, y_bearing = 0, 0
|
||||
|
||||
# Get rotations and translations
|
||||
x, y, dx, dy, rotate = [], [], [], [], [0]
|
||||
@ -89,19 +87,8 @@ def text(svg, node, font_size):
|
||||
letter_spacing = (text_length - width) / spaces_count
|
||||
width = text_length
|
||||
|
||||
# Align text box horizontally
|
||||
x_align = 0
|
||||
text_anchor = node.get('text-anchor')
|
||||
# TODO: use real values
|
||||
ascent, descent = font_size * .8, font_size * .2
|
||||
if text_anchor == 'middle':
|
||||
x_align = - (width / 2 + x_bearing)
|
||||
if letter_spacing and node.text:
|
||||
x_align -= (len(node.text) - 1) * letter_spacing / 2
|
||||
elif text_anchor == 'end':
|
||||
x_align = - (width + x_bearing)
|
||||
if letter_spacing and node.text:
|
||||
x_align -= (len(node.text) - 1) * letter_spacing
|
||||
|
||||
# Align text box vertically
|
||||
# TODO: This is a hack. Other baseline alignment tags are not supported.
|
||||
@ -111,11 +98,11 @@ def text(svg, node, font_size):
|
||||
alignment_baseline = node.get(
|
||||
'dominant-baseline', node.get('alignment-baseline'))
|
||||
if display_anchor == 'middle':
|
||||
y_align = -height / 2 - y_bearing
|
||||
y_align = -height / 2
|
||||
elif display_anchor == 'top':
|
||||
y_align = -y_bearing
|
||||
pass
|
||||
elif display_anchor == 'bottom':
|
||||
y_align = -height - y_bearing
|
||||
y_align = -height
|
||||
elif alignment_baseline in ('central', 'middle'):
|
||||
# TODO: This is wrong, we use font top-to-bottom
|
||||
y_align = (ascent + descent) / 2 - descent
|
||||
@ -157,16 +144,14 @@ def text(svg, node, font_size):
|
||||
width *= scale_x
|
||||
if i:
|
||||
x += letter_spacing
|
||||
svg.cursor_position = x + width, y
|
||||
|
||||
x_position = x + svg.cursor_d_position[0] + x_align
|
||||
x_position = x + svg.cursor_d_position[0]
|
||||
y_position = y + svg.cursor_d_position[1] + y_align
|
||||
cursor_position = x + width, y
|
||||
angle = last_r if r is None else r
|
||||
points = (
|
||||
(cursor_position[0] + x_align + svg.cursor_d_position[0],
|
||||
cursor_position[1] + y_align + svg.cursor_d_position[1]),
|
||||
(cursor_position[0] + x_align + width + svg.cursor_d_position[0],
|
||||
cursor_position[1] + y_align + height + svg.cursor_d_position[1]))
|
||||
(x_position, y_position),
|
||||
(x_position + width, y_position - height))
|
||||
node.text_bounding_box = extend_bounding_box(
|
||||
node.text_bounding_box, points)
|
||||
|
||||
@ -179,7 +164,6 @@ def text(svg, node, font_size):
|
||||
emojis = draw_first_line(
|
||||
svg.stream, TextBox(layout, style), 'none', 'none', matrix)
|
||||
emoji_lines.append((font_size, x, y, emojis))
|
||||
svg.cursor_position = cursor_position
|
||||
|
||||
svg.stream.end_text()
|
||||
svg.stream.pop_state()
|
||||
|
Loading…
Reference in New Issue
Block a user