def gradient_average_color(colors, positions):
    """
    https://drafts.csswg.org/css-images-3/#gradient-average-color
    """
    # TODO: handle color spaces.
    nb_stops = len(positions)
    assert nb_stops > 1
    assert nb_stops == len(colors)
    total_length = positions[-1] - positions[0]
    if total_length == 0:
        positions = list(range(nb_stops))
        total_length = nb_stops - 1
    premul_r = [r * a for r, g, b, a in colors]
    premul_g = [g * a for r, g, b, a in colors]
    premul_b = [b * a for r, g, b, a in colors]
    alpha = [a for r, g, b, a in colors]
    result_r = result_g = result_b = result_a = 0
    total_weight = 2 * total_length
    for i, position in enumerate(positions[1:], 1):
        weight = (position - positions[i - 1]) / total_weight
        for j in (i - 1, i):
            result_r += premul_r[j] * weight
            result_g += premul_g[j] * weight
            result_b += premul_b[j] * weight
            result_a += alpha[j] * weight
    # Un-premultiply.
    if result_a == 0:
        return parse_color('transparent')
    else:
        return parse_color(
            f'rgb({result_r / result_a * 255} {result_g / result_a * 255} '
            f'{result_b / result_a * 255}/{ result_a })')
https://drafts.csswg.org/css-images-3/#gradient-average-color
weasyprint/images.py