mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-09-11 20:47:56 +03:00
Fix and test repeating linear gradients
This commit is contained in:
parent
c4c23fca73
commit
88dc3df4aa
@ -173,6 +173,42 @@ def test_linear_gradient_transform(assert_pixels):
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_transform_repeat(assert_pixels):
|
||||
assert_pixels('''
|
||||
__________
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
GGGGGGGGGG
|
||||
vvvvvvvvvv
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
GGGGGGGGGG
|
||||
vvvvvvvvvv
|
||||
__________
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px 10px}
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="grad" x1="0" y1="0" x2="0" y2="1"
|
||||
gradientUnits="objectBoundingBox" spreadMethod="repeat"
|
||||
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>
|
||||
<stop stop-color="lime" offset="50%"></stop>
|
||||
<stop stop-color="lime" offset="75%"></stop>
|
||||
<stop stop-color="rgb(128,0,128)" offset="75%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="0" y="1" width="10" height="8" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_transform_userspace(assert_pixels):
|
||||
assert_pixels('''
|
||||
@ -209,6 +245,42 @@ def test_linear_gradient_transform_userspace(assert_pixels):
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_transform_repeat_userspace(assert_pixels):
|
||||
assert_pixels('''
|
||||
__________
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
GGGGGGGGGG
|
||||
vvvvvvvvvv
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
GGGGGGGGGG
|
||||
vvvvvvvvvv
|
||||
__________
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px 10px}
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="grad" x1="0" y1="0" x2="0" y2="8"
|
||||
gradientUnits="userSpaceOnUse" spreadMethod="repeat"
|
||||
gradientTransform="matrix(0.5, 0, 0, 0.5, 0, 5)">
|
||||
<stop stop-color="blue" offset="25%"></stop>
|
||||
<stop stop-color="red" offset="25%"></stop>
|
||||
<stop stop-color="red" offset="50%"></stop>
|
||||
<stop stop-color="lime" offset="50%"></stop>
|
||||
<stop stop-color="lime" offset="75%"></stop>
|
||||
<stop stop-color="rgb(128,0,128)" offset="75%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="0" y="1" width="10" height="8" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_repeat(assert_pixels):
|
||||
assert_pixels('''
|
||||
|
@ -134,6 +134,12 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
positions.append(positions[-1] + 1)
|
||||
colors.append(colors[-1])
|
||||
|
||||
if 'gradientTransform' in gradient.attrib:
|
||||
transform_matrix = transform(
|
||||
gradient.get('gradientTransform'), font_size,
|
||||
svg.normalized_diagonal)
|
||||
matrix = transform_matrix @ matrix
|
||||
|
||||
if gradient.tag == 'linearGradient':
|
||||
shading_type = 2
|
||||
x1, y1 = (
|
||||
@ -143,7 +149,7 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
size(gradient.get('x2', '100%'), font_size, width),
|
||||
size(gradient.get('y2', 0), font_size, height))
|
||||
positions, colors, coords = spread_linear_gradient(
|
||||
spread, positions, colors, x1, y1, x2, y2, matrix)
|
||||
spread, positions, colors, x1, y1, x2, y2, bounding_box, matrix)
|
||||
else:
|
||||
assert gradient.tag == 'radialGradient'
|
||||
shading_type = 3
|
||||
@ -178,19 +184,15 @@ 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
|
||||
bx1, by1 = 0, 0
|
||||
if 'gradientTransform' in gradient.attrib:
|
||||
transform_matrix = transform(
|
||||
gradient.get('gradientTransform'), font_size,
|
||||
svg.normalized_diagonal)
|
||||
matrix = transform_matrix @ matrix
|
||||
x1, y1 = transform_matrix.invert.transform_point(x1, y1)
|
||||
x2, y2 = transform_matrix.invert.transform_point(width, height)
|
||||
width, height = x2 - x1, y2 - y1
|
||||
bx1, by1 = transform_matrix.invert.transform_point(bx1, by1)
|
||||
bx2, by2 = transform_matrix.invert.transform_point(width, height)
|
||||
width, height = bx2 - bx1, by2 - by1
|
||||
|
||||
pattern = svg.stream.add_pattern(
|
||||
x1, y1, width, height, width, height, matrix @ svg.stream.ctm)
|
||||
group = pattern.add_group(x1, y1, width, height)
|
||||
bx1, by1, width, height, width, height, matrix @ svg.stream.ctm)
|
||||
group = pattern.add_group(bx1, by1, width, height)
|
||||
|
||||
domain = (positions[0], positions[-1])
|
||||
extend = spread not in ('repeat', 'reflect')
|
||||
@ -205,7 +207,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(x1, y1, width, height)
|
||||
alpha_stream = group.set_alpha_state(bx1, by1, width, height)
|
||||
domain = (positions[0], positions[-1])
|
||||
extend = spread not in ('repeat', 'reflect')
|
||||
encode = (len(colors) - 1) * (0, 1)
|
||||
@ -227,7 +229,8 @@ def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
|
||||
return True
|
||||
|
||||
|
||||
def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2, matrix):
|
||||
def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2,
|
||||
bounding_box, matrix):
|
||||
"""Repeat linear gradient."""
|
||||
# TODO: merge with LinearGradient.layout
|
||||
from ..images import gradient_average_color, normalize_stop_positions
|
||||
@ -242,7 +245,6 @@ def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2, matrix):
|
||||
|
||||
# Define defined gradient length and steps between positions
|
||||
stop_length = last - first
|
||||
assert stop_length > 0
|
||||
position_steps = [
|
||||
positions[i + 1] - positions[i]
|
||||
for i in range(len(positions) - 1)]
|
||||
@ -262,17 +264,33 @@ def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2, matrix):
|
||||
[0] + position_steps + [0] + position_steps[::-1])
|
||||
previous_colors = cycle(colors + colors[::-1])
|
||||
|
||||
# Add colors after last step
|
||||
# Normalize bounding box
|
||||
bx1, by1, bw, bh = bounding_box
|
||||
bx1, bx2 = (bx1, bx1 + bw) if bw > 0 else (bx1 + bw, bx1)
|
||||
by1, by2 = (by1, by1 + bh) if bh > 0 else (by1 + bh, by1)
|
||||
|
||||
# Transform gradient vector coordinates
|
||||
tx1, ty1 = matrix.transform_point(x1, y1)
|
||||
tx2, ty2 = matrix.transform_point(x2, y2)
|
||||
while last < hypot(tx2 - tx1, ty2 - ty1):
|
||||
|
||||
# Find the extremities of the repeating vector, by projecting the
|
||||
# bounding box corners on the gradient vector
|
||||
xb, yb = tx1, ty1
|
||||
xv, yv = tx2 - tx1, ty2 - ty1
|
||||
xa1, xa2 = (bx1, bx2) if tx1 < tx2 else (bx2, bx1)
|
||||
ya1, ya2 = (by1, by2) if ty1 < ty2 else (by2, by1)
|
||||
min_vector = ((xa1 - xb) * xv + (ya1 - yb) * yv) / hypot(xv, yv) ** 2
|
||||
max_vector = ((xa2 - xb) * xv + (ya2 - yb) * yv) / hypot(xv, yv) ** 2
|
||||
|
||||
# Add colors after last step
|
||||
while last < max_vector:
|
||||
step = next(next_steps)
|
||||
colors.append(next(next_colors))
|
||||
positions.append(positions[-1] + step)
|
||||
last += step * stop_length
|
||||
|
||||
# Add colors before last step
|
||||
while first > 0:
|
||||
# Add colors before first step
|
||||
while first > min_vector:
|
||||
step = next(previous_steps)
|
||||
colors.insert(0, next(previous_colors))
|
||||
positions.insert(0, positions[0] - step)
|
||||
|
Loading…
Reference in New Issue
Block a user