mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-09-11 20:47:56 +03:00
Fix and clean many linear gradients in SVG
This commit is contained in:
parent
df97154331
commit
e2b30af70b
@ -136,14 +136,14 @@ def test_linear_gradient_multicolor_userspace(assert_pixels):
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_transform(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
GGGGGGGGGG
|
||||
vvvvvvvvvv
|
||||
vvvvvvvvvv
|
||||
vvvvvvvvvv
|
||||
vvvvvvvvvv
|
||||
vvvvvvvvvv
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px 8px}
|
||||
@ -152,7 +152,8 @@ def test_linear_gradient_transform(assert_pixels):
|
||||
<svg width="10px" height="8px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="grad" x1="0" y1="0" x2="0" y2="1"
|
||||
gradientUnits="objectBoundingBox" gradientTransform="scale(0.5)">
|
||||
gradientUnits="objectBoundingBox"
|
||||
gradientTransform="matrix(0.5, 0, 0, 0.5, 0, 0.5)">
|
||||
<stop stop-color="blue" offset="25%"></stop>
|
||||
<stop stop-color="red" offset="25%"></stop>
|
||||
<stop stop-color="red" offset="50%"></stop>
|
||||
@ -207,7 +208,6 @@ def test_linear_gradient_repeat(assert_pixels):
|
||||
''')
|
||||
|
||||
|
||||
@pytest.mark.xfail
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_repeat_long(assert_pixels):
|
||||
assert_pixels('''
|
||||
|
@ -82,7 +82,6 @@ def test_stroke_fill_opacity(assert_same_renderings):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.xfail
|
||||
@assert_no_logs
|
||||
def test_pattern_gradient_stroke_fill_opacity(assert_same_renderings):
|
||||
assert_same_renderings(
|
||||
|
@ -390,7 +390,7 @@ def draw_background_image(stream, layer, image_rendering):
|
||||
matrix = Matrix(e=position_x + positioning_x, f=position_y + positioning_y)
|
||||
matrix @= stream.ctm
|
||||
pattern = stream.add_pattern(
|
||||
image_width, image_height, repeat_width, repeat_height, matrix)
|
||||
0, 0, image_width, image_height, repeat_width, repeat_height, matrix)
|
||||
group = pattern.add_group([0, 0, repeat_width, repeat_height])
|
||||
|
||||
with stacked(stream):
|
||||
|
@ -466,7 +466,8 @@ class Stream(pydyf.Stream):
|
||||
self._images[image_name] = xobject
|
||||
return image_name
|
||||
|
||||
def add_pattern(self, width, height, repeat_width, repeat_height, matrix):
|
||||
def add_pattern(self, x, y, width, height, repeat_width, repeat_height,
|
||||
matrix):
|
||||
states = pydyf.Dictionary()
|
||||
x_objects = pydyf.Dictionary()
|
||||
patterns = pydyf.Dictionary()
|
||||
@ -481,7 +482,7 @@ class Stream(pydyf.Stream):
|
||||
extra = pydyf.Dictionary({
|
||||
'Type': '/Pattern',
|
||||
'PatternType': 1,
|
||||
'BBox': pydyf.Array([0, 0, width, height]),
|
||||
'BBox': pydyf.Array([x, y, width, height]),
|
||||
'XStep': repeat_width,
|
||||
'YStep': repeat_height,
|
||||
'TilingType': 1,
|
||||
|
@ -105,7 +105,6 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
if not is_valid_bounding_box(bounding_box):
|
||||
return False
|
||||
x, y = bounding_box[0], bounding_box[1]
|
||||
matrix = Matrix(e=x, f=y)
|
||||
if gradient.get('gradientUnits') == 'userSpaceOnUse':
|
||||
width, height = svg.inner_width, svg.inner_height
|
||||
else:
|
||||
@ -133,6 +132,10 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
positions.append(positions[-1] + 1)
|
||||
colors.append(colors[-1])
|
||||
|
||||
if gradient.get('gradientUnits') == 'userSpaceOnUse':
|
||||
matrix = Matrix()
|
||||
else:
|
||||
matrix = Matrix(a=width, d=height)
|
||||
if gradient.tag == 'linearGradient':
|
||||
shading_type = 2
|
||||
x1, y1 = (
|
||||
@ -141,22 +144,8 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
x2, y2 = (
|
||||
size(gradient.get('x2', '100%'), font_size, 1),
|
||||
size(gradient.get('y2', 0), font_size, 1))
|
||||
if gradient.get('gradientUnits') == 'userSpaceOnUse':
|
||||
x1 -= x
|
||||
y1 -= y
|
||||
x2 -= x
|
||||
y2 -= y
|
||||
else:
|
||||
length = min(width, height)
|
||||
x1 *= length
|
||||
y1 *= length
|
||||
x2 *= length
|
||||
y2 *= length
|
||||
a = (width / height) if height < width else 1
|
||||
d = (height / width) if height > width else 1
|
||||
matrix = Matrix(a=a, d=d) @ matrix
|
||||
positions, colors, coords = spread_linear_gradient(
|
||||
spread, positions, colors, x1, y1, x2, y2)
|
||||
spread, positions, colors, x1, y1, x2, y2, matrix)
|
||||
else:
|
||||
assert gradient.tag == 'radialGradient'
|
||||
shading_type = 3
|
||||
@ -168,24 +157,11 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
size(gradient.get('fx', cx), font_size, width),
|
||||
size(gradient.get('fy', cy), font_size, height))
|
||||
fr = size(gradient.get('fr', 0), font_size, 1)
|
||||
if gradient.get('gradientUnits') == 'userSpaceOnUse':
|
||||
cx -= x
|
||||
cy -= y
|
||||
fx -= x
|
||||
fy -= y
|
||||
else:
|
||||
length = min(width, height)
|
||||
cx *= length
|
||||
cy *= length
|
||||
r *= length
|
||||
fx *= length
|
||||
fy *= length
|
||||
fr *= length
|
||||
a = (width / height) if height < width else 1
|
||||
d = (height / width) if height > width else 1
|
||||
matrix = Matrix(a=a, d=d) @ matrix
|
||||
positions, colors, coords = spread_radial_gradient(
|
||||
spread, positions, colors, fx, fy, fr, cx, cy, r, width, height)
|
||||
spread, positions, colors, fx, fy, fr, cx, cy, r, width, height,
|
||||
matrix)
|
||||
|
||||
matrix @= svg.stream.ctm
|
||||
|
||||
alphas = [color[3] for color in colors]
|
||||
alpha_couples = [
|
||||
@ -206,18 +182,19 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
if 0 not in (a0, a1) and (a0, a1) != (1, 1):
|
||||
color_couples[i][2] = a0 / a1
|
||||
|
||||
x1, y1 = 0, 0
|
||||
x1, y1 = x, y
|
||||
if 'gradientTransform' in gradient.attrib:
|
||||
transform_matrix = transform(
|
||||
gradient.get('gradientTransform'), font_size,
|
||||
svg.normalized_diagonal)
|
||||
x1, y1 = transform_matrix.invert.transform_point(0, 0)
|
||||
x2, y2 = transform_matrix.invert.transform_point(width, height)
|
||||
x1, y1 = transform_matrix.invert.transform_point(x1, y1)
|
||||
x2, y2 = transform_matrix.invert.transform_point(
|
||||
x1 + width, y1 + height)
|
||||
width, height = x2 - x1, y2 - y1
|
||||
matrix = transform_matrix @ matrix
|
||||
|
||||
matrix = matrix @ svg.stream.ctm
|
||||
pattern = svg.stream.add_pattern(width, height, width, height, matrix)
|
||||
pattern = svg.stream.add_pattern(
|
||||
x1, y1, width, height, width, height, matrix)
|
||||
group = pattern.add_group([x1, y1, width, height])
|
||||
|
||||
domain = (positions[0], positions[-1])
|
||||
@ -233,8 +210,7 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
shading_type, 'RGB', domain, coords, extend, function)
|
||||
|
||||
if any(alpha != 1 for alpha in alphas):
|
||||
alpha_stream = group.set_alpha_state(
|
||||
0, 0, svg.concrete_width, svg.concrete_height)
|
||||
alpha_stream = group.set_alpha_state(x1, y1, width, height)
|
||||
domain = (positions[0], positions[-1])
|
||||
extend = spread not in ('repeat', 'reflect')
|
||||
encode = (len(colors) - 1) * (0, 1)
|
||||
@ -256,7 +232,7 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
return True
|
||||
|
||||
|
||||
def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2):
|
||||
def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2, matrix):
|
||||
"""Repeat linear gradient."""
|
||||
# TODO: merge with LinearGradient.layout
|
||||
from ..images import gradient_average_color, normalize_stop_positions
|
||||
@ -292,7 +268,9 @@ def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2):
|
||||
previous_colors = cycle(colors + colors[::-1])
|
||||
|
||||
# Add colors after last step
|
||||
while last < hypot(x2 - x1, y2 - y1):
|
||||
tx1, ty1 = matrix.transform_point(x1, y1)
|
||||
tx2, ty2 = matrix.transform_point(x2, y2)
|
||||
while last < hypot(tx2 - tx1, ty2 - ty1):
|
||||
step = next(next_steps)
|
||||
colors.append(next(next_colors))
|
||||
positions.append(positions[-1] + step)
|
||||
@ -312,7 +290,7 @@ def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2):
|
||||
|
||||
|
||||
def spread_radial_gradient(spread, positions, colors, fx, fy, fr, cx, cy, r,
|
||||
width, height):
|
||||
width, height, matrix):
|
||||
"""Repeat radial gradient."""
|
||||
# TODO: merge with RadialGradient._repeat
|
||||
from ..images import gradient_average_color, normalize_stop_positions
|
||||
@ -328,10 +306,11 @@ def spread_radial_gradient(spread, positions, colors, fx, fy, fr, cx, cy, r,
|
||||
|
||||
# Get the maximum distance between the center and the corners, to find
|
||||
# how many times we have to repeat the colors outside
|
||||
tw, th = matrix.transform_point(width, height)
|
||||
max_distance = max(
|
||||
hypot(width - fx, height - fy),
|
||||
hypot(width - fx, -fy),
|
||||
hypot(-fx, height - fy),
|
||||
hypot(tw - fx, th - fy),
|
||||
hypot(tw - fx, -fy),
|
||||
hypot(-fx, th - fy),
|
||||
hypot(-fx, -fy))
|
||||
repeat_after = ceil((max_distance - r) / gradient_length)
|
||||
if repeat_after > 0:
|
||||
@ -465,7 +444,8 @@ def draw_pattern(svg, node, pattern, font_size, opacity, stroke):
|
||||
|
||||
matrix = matrix @ svg.stream.ctm
|
||||
stream_pattern = svg.stream.add_pattern(
|
||||
pattern_width, pattern_height, pattern_width, pattern_height, matrix)
|
||||
0, 0, pattern_width, pattern_height, pattern_width, pattern_height,
|
||||
matrix)
|
||||
stream_pattern.set_alpha(opacity)
|
||||
|
||||
group = stream_pattern.add_group([0, 0, pattern_width, pattern_height])
|
||||
|
Loading…
Reference in New Issue
Block a user