Пример #1
0
def test_text():
    document = pydyf.PDF()

    font = pydyf.Dictionary({
        'Type': '/Font',
        'Subtype': '/Type1',
        'Name': '/F1',
        'BaseFont': '/Helvetica',
        'Encoding': '/MacRomanEncoding',
    })
    document.add_object(font)

    draw = pydyf.Stream()
    draw.begin_text()
    draw.set_font_size('F1', 200)
    draw.text_matrix(1, 0, 0, 1, -20, 5)
    draw.show_text(pydyf.String('l'))
    draw.show_text(pydyf.String('É'))
    draw.end_text()

    document.add_object(draw)

    document.add_page(
        pydyf.Dictionary({
            'Type':
            '/Page',
            'Parent':
            document.pages.reference,
            'Contents':
            draw.reference,
            'MediaBox':
            pydyf.Array([0, 0, 10, 10]),
            'Resources':
            pydyf.Dictionary({
                'ProcSet': pydyf.Array(['/PDF', '/Text']),
                'Font': pydyf.Dictionary({'F1': font.reference}),
            }),
        }))

    assert_pixels(
        document, '''
        KKKKKKKKKK
        KKKKKKKKKK
        KKKKKKKKKK
        KKKKKKKKKK
        KKKKKKKKKK
        __________
        __________
        __________
        __________
        __________
    ''')
Пример #2
0
def apply_filters(svg, node, filter_node, font_size):
    """Apply filters defined in given filter node."""
    for child in filter_node:
        if child.tag == 'feOffset':
            if filter_node.get('primitiveUnits') == 'objectBoundingBox':
                bounding_box = svg.calculate_bounding_box(node, font_size)
                if is_valid_bounding_box(bounding_box):
                    _, _, width, height = bounding_box
                    dx = size(child.get('dx', 0), font_size, 1) * width
                    dy = size(child.get('dy', 0), font_size, 1) * height
                else:
                    dx = dy = 0
            else:
                dx, dy = svg.point(child.get('dx', 0), child.get('dy', 0),
                                   font_size)
            svg.stream.transform(1, 0, 0, 1, dx, dy)
        elif child.tag == 'feBlend':
            mode = child.get('mode', 'normal')
            mode = mode.replace('-', ' ').title().replace(' ', '')
            blend_mode = pydyf.Dictionary({
                'Type': '/ExtGState',
                'BM': f'/{mode}',
            })
            blend_mode_id = f'bm{len(svg.stream._alpha_states)}'
            svg.stream._alpha_states[blend_mode_id] = blend_mode
            svg.stream.set_state(blend_mode_id)
Пример #3
0
def test_set_color_rgb_stroke():
    document = pydyf.PDF()

    draw = pydyf.Stream()
    draw.rectangle(2, 2, 5, 6)
    draw.set_line_width(2)
    draw.set_color_rgb(0, 0, 255, stroke=True)
    draw.stroke()
    document.add_object(draw)

    document.add_page(pydyf.Dictionary({
        'Type': '/Page',
        'Parent': document.pages.reference,
        'Contents': draw.reference,
        'MediaBox': pydyf.Array([0, 0, 10, 10]),
    }))

    assert_pixels(document, '''
        __________
        _BBBBBBB__
        _BBBBBBB__
        _BB___BB__
        _BB___BB__
        _BB___BB__
        _BB___BB__
        _BBBBBBB__
        _BBBBBBB__
        __________
    ''')
Пример #4
0
def test_fill():
    document = pydyf.PDF()

    draw = pydyf.Stream()
    draw.rectangle(2, 2, 5, 6)
    draw.fill()
    document.add_object(draw)

    document.add_page(pydyf.Dictionary({
        'Type': '/Page',
        'Parent': document.pages.reference,
        'Contents': draw.reference,
        'MediaBox': pydyf.Array([0, 0, 10, 10]),
    }))

    assert_pixels(document, '''
        __________
        __________
        __KKKKK___
        __KKKKK___
        __KKKKK___
        __KKKKK___
        __KKKKK___
        __KKKKK___
        __________
        __________
    ''')
Пример #5
0
def test_line_to():
    document = pydyf.PDF()

    draw = pydyf.Stream()
    draw.move_to(2, 2)
    draw.set_line_width(2)
    draw.line_to(2, 5)
    draw.stroke()
    document.add_object(draw)

    document.add_page(pydyf.Dictionary({
        'Type': '/Page',
        'Parent': document.pages.reference,
        'Contents': draw.reference,
        'MediaBox': pydyf.Array([0, 0, 10, 10]),
    }))

    assert_pixels(document, '''
        __________
        __________
        __________
        __________
        __________
        _KK_______
        _KK_______
        _KK_______
        __________
        __________
    ''')
Пример #6
0
def test_fill_stroke_and_close():
    document = pydyf.PDF()

    draw = pydyf.Stream()
    draw.move_to(2, 2)
    draw.line_to(2, 8)
    draw.line_to(7, 8)
    draw.line_to(7, 2)
    draw.set_color_rgb(255, 0, 0)
    draw.set_color_rgb(0, 0, 255, stroke=True)
    draw.set_line_width(2)
    draw.fill_stroke_and_close()
    document.add_object(draw)

    document.add_page(pydyf.Dictionary({
        'Type': '/Page',
        'Parent': document.pages.reference,
        'Contents': draw.reference,
        'MediaBox': pydyf.Array([0, 0, 10, 10]),
    }))

    assert_pixels(document, '''
        __________
        _BBBBBBB__
        _BBBBBBB__
        _BBRRRBB__
        _BBRRRBB__
        _BBRRRBB__
        _BBRRRBB__
        _BBBBBBB__
        _BBBBBBB__
        __________
    ''')
Пример #7
0
def test_clip_even_odd():
    document = pydyf.PDF()

    draw = pydyf.Stream()
    draw.rectangle(3, 3, 5, 6)
    draw.rectangle(4, 3, 2, 6)
    draw.clip(even_odd=True)
    draw.end()
    draw.move_to(0, 5)
    draw.line_to(10, 5)
    draw.set_color_rgb(255, 0, 0, stroke=True)
    draw.set_line_width(2)
    draw.stroke()
    document.add_object(draw)

    document.add_page(pydyf.Dictionary({
        'Type': '/Page',
        'Parent': document.pages.reference,
        'Contents': draw.reference,
        'MediaBox': pydyf.Array([0, 0, 10, 10]),
    }))

    assert_pixels(document, '''
        __________
        __________
        __________
        __________
        ___R__RR__
        ___R__RR__
        __________
        __________
        __________
        __________
    ''')
Пример #8
0
def paint_mask(svg, node, mask, font_size):
    """Apply given mask node."""
    mask._etree_node.tag = 'g'

    if mask.get('maskUnits') == 'userSpaceOnUse':
        width_ref, height_ref = svg.concrete_width, svg.concrete_height
    else:
        width_ref, height_ref = svg.point(node.get('width'),
                                          node.get('height'), font_size)

    mask.attrib['x'] = size(mask.get('x', '-10%'), font_size, width_ref)
    mask.attrib['y'] = size(mask.get('y', '-10%'), font_size, height_ref)
    mask.attrib['height'] = size(mask.get('height', '120%'), font_size,
                                 height_ref)
    mask.attrib['width'] = size(mask.get('width', '120%'), font_size,
                                width_ref)

    if mask.get('maskUnits') == 'userSpaceOnUse':
        x, y = mask.get('x'), mask.get('y')
        width, height = mask.get('width'), mask.get('height')
        mask.attrib['viewBox'] = f'{x} {y} {width} {height}'
    else:
        x, y = 0, 0
        width, height = width_ref, height_ref

    alpha_stream = svg.stream.add_group([x, y, width, height])
    state = pydyf.Dictionary({
        'Type':
        '/ExtGState',
        'SMask':
        pydyf.Dictionary({
            'Type': '/Mask',
            'S': '/Luminance',
            'G': alpha_stream,
        }),
        'ca':
        1,
        'AIS':
        'false',
    })
    svg.stream.set_state(state)

    svg_stream = svg.stream
    svg.stream = alpha_stream
    svg.draw_node(mask, font_size)
    svg.stream = svg_stream
Пример #9
0
def test_set_state():
    document = pydyf.PDF()

    graphic_state = pydyf.Dictionary({
        'Type': '/ExtGState',
        'LW': 2,
    })
    document.add_object(graphic_state)

    draw = pydyf.Stream()
    draw.rectangle(2, 2, 5, 6)
    draw.set_state('GS')
    draw.stroke()
    document.add_object(draw)

    document.add_page(
        pydyf.Dictionary({
            'Type':
            '/Page',
            'Parent':
            document.pages.reference,
            'Contents':
            draw.reference,
            'MediaBox':
            pydyf.Array([0, 0, 10, 10]),
            'Resources':
            pydyf.Dictionary({
                'ExtGState':
                pydyf.Dictionary({'GS': graphic_state.reference}),
            }),
        }))

    assert_pixels(
        document, '''
        __________
        _KKKKKKK__
        _KKKKKKK__
        _KK___KK__
        _KK___KK__
        _KK___KK__
        _KK___KK__
        _KKKKKKK__
        _KKKKKKK__
        __________
    ''')
Пример #10
0
    def draw(self, stream, concrete_width, concrete_height, _image_rendering):
        # TODO: handle color spaces
        scale_y, type_, points, positions, colors = self.layout(
            concrete_width, concrete_height)

        if type_ == 'solid':
            stream.rectangle(0, 0, concrete_width, concrete_height)
            red, green, blue, alpha = colors[0]
            stream.set_color_rgb(red, green, blue)
            if alpha != 1:
                stream.set_alpha(alpha, stroke=False)
            stream.fill()
            return

        alphas = [color[3] for color in colors]
        alpha_couples = [(alphas[i], alphas[i + 1])
                         for i in range(len(alphas) - 1)]
        color_couples = [[colors[i][:3], colors[i + 1][:3], 1]
                         for i in range(len(colors) - 1)]

        # Premultiply colors
        for i, alpha in enumerate(alphas):
            if alpha == 0:
                if i > 0:
                    color_couples[i - 1][1] = color_couples[i - 1][0]
                if i < len(colors) - 1:
                    color_couples[i][0] = color_couples[i][1]
        for i, (a0, a1) in enumerate(alpha_couples):
            if 0 not in (a0, a1) and (a0, a1) != (1, 1):
                color_couples[i][2] = a0 / a1

        shading = stream.add_shading()
        shading['ShadingType'] = 2 if type_ == 'linear' else 3
        shading['ColorSpace'] = '/DeviceRGB'
        shading['Domain'] = pydyf.Array([positions[0], positions[-1]])
        shading['Coords'] = pydyf.Array(points)
        shading['Function'] = pydyf.Dictionary({
            'FunctionType':
            3,
            'Domain':
            pydyf.Array([positions[0], positions[-1]]),
            'Encode':
            pydyf.Array((len(colors) - 1) * [0, 1]),
            'Bounds':
            pydyf.Array(positions[1:-1]),
            'Functions':
            pydyf.Array([
                pydyf.Dictionary({
                    'FunctionType': 2,
                    'Domain': pydyf.Array([0, 1]),
                    'C0': pydyf.Array(c0),
                    'C1': pydyf.Array(c1),
                    'N': n,
                }) for c0, c1, n in color_couples
            ]),
        })
        if not self.repeating:
            shading['Extend'] = pydyf.Array([b'true', b'true'])
        stream.transform(d=scale_y)

        if any(alpha != 1 for alpha in alphas):
            alpha_stream = stream.add_group(
                [0, 0, concrete_width, concrete_height])
            alpha_state = pydyf.Dictionary({
                'Type':
                '/ExtGState',
                'SMask':
                pydyf.Dictionary({
                    'Type': '/Mask',
                    'S': '/Luminosity',
                    'G': alpha_stream,
                }),
                'ca':
                1,
                'AIS':
                'false',
            })
            stream.set_state(alpha_state)

            alpha_shading = alpha_stream.add_shading()
            alpha_shading['ShadingType'] = 2 if type_ == 'linear' else 3
            alpha_shading['ColorSpace'] = '/DeviceGray'
            alpha_shading['Domain'] = pydyf.Array(
                [positions[0], positions[-1]])
            alpha_shading['Coords'] = pydyf.Array(points)
            alpha_shading['Function'] = pydyf.Dictionary({
                'FunctionType':
                3,
                'Domain':
                pydyf.Array([positions[0], positions[-1]]),
                'Encode':
                pydyf.Array((len(colors) - 1) * [0, 1]),
                'Bounds':
                pydyf.Array(positions[1:-1]),
                'Functions':
                pydyf.Array([
                    pydyf.Dictionary({
                        'FunctionType': 2,
                        'Domain': pydyf.Array([0, 1]),
                        'C0': pydyf.Array([c0]),
                        'C1': pydyf.Array([c1]),
                        'N': 1,
                    }) for c0, c1 in alpha_couples
                ]),
            })
            if not self.repeating:
                alpha_shading['Extend'] = pydyf.Array([b'true', b'true'])
            alpha_stream.transform(d=scale_y)
            alpha_stream.stream = [f'/{alpha_shading.id} sh']

        stream.shading(shading.id)
Пример #11
0
def draw_gradient(svg, node, gradient, font_size, opacity, stroke):
    """Draw given gradient node."""
    # TODO: merge with Gradient.draw
    from ..document import Matrix

    positions = []
    colors = []
    for child in gradient:
        positions.append(
            max(positions[-1] if positions else 0,
                size(child.get('offset'), font_size, 1)))
        stop_opacity = float(child.get('stop-opacity', 1)) * opacity
        stop_color = color(child.get('stop-color', 'black'))
        if stop_opacity < 1:
            stop_color = tuple(stop_color[:3] +
                               (stop_color[3] * stop_opacity, ))
        colors.append(stop_color)

    if not colors:
        return False
    elif len(colors) == 1:
        red, green, blue, alpha = colors[0]
        svg.stream.set_color_rgb(red, green, blue)
        if alpha != 1:
            svg.stream.set_alpha(alpha, stroke=stroke)
        return True

    bounding_box = svg.calculate_bounding_box(node, font_size, stroke)
    if not is_valid_bounding_box(bounding_box):
        return False
    x, y = bounding_box[0], bounding_box[1]
    node_x, node_y = svg.point(node.get('x'), node.get('y'), font_size)
    matrix = Matrix()
    if gradient.get('gradientUnits') == 'userSpaceOnUse':
        viewbox = svg.get_viewbox()
        if viewbox:
            width, height = viewbox[2], viewbox[3]
        else:
            width, height = svg.concrete_width, svg.concrete_height
    else:
        width, height = bounding_box[2], bounding_box[3]

    spread = gradient.get('spreadMethod', 'pad')
    if spread not in ('repeat', 'reflect'):
        # Add explicit colors at boundaries if needed, because PDF doesn’t
        # extend color stops that are not displayed
        if positions[0] == positions[1]:
            if gradient.tag == 'radialGradient':
                # Avoid negative radius for radial gradients
                positions.insert(0, 0)
            else:
                positions.insert(0, positions[0] - 1)
            colors.insert(0, colors[0])
        if positions[-2] == positions[-1]:
            positions.append(positions[-1] + 1)
            colors.append(colors[-1])

    if gradient.tag == 'linearGradient':
        shading_type = 2
        x1, y1 = (size(gradient.get('x1', 0), font_size,
                       1), size(gradient.get('y1', 0), font_size, 1))
        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)
    else:
        assert gradient.tag == 'radialGradient'
        shading_type = 3
        cx, cy = (size(gradient.get('cx', '50%'), font_size,
                       1), size(gradient.get('cy', '50%'), font_size, 1))
        r = size(gradient.get('r', '50%'), font_size, 1)
        fx, fy = (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)

    alphas = [color[3] for color in colors]
    alpha_couples = [(alphas[i], alphas[i + 1])
                     for i in range(len(alphas) - 1)]
    color_couples = [[colors[i][:3], colors[i + 1][:3], 1]
                     for i in range(len(colors) - 1)]

    # Premultiply colors
    for i, alpha in enumerate(alphas):
        if alpha == 0:
            if i > 0:
                color_couples[i - 1][1] = color_couples[i - 1][0]
            if i < len(colors) - 1:
                color_couples[i][0] = color_couples[i][1]
    for i, (a0, a1) in enumerate(alpha_couples):
        if 0 not in (a0, a1) and (a0, a1) != (1, 1):
            color_couples[i][2] = a0 / a1

    if 'gradientTransform' in gradient.attrib:
        transform_matrix = transform(gradient.get('gradientTransform'),
                                     font_size, svg.normalized_diagonal)
        matrix = transform_matrix @ matrix

    a, b, c, d, e, f = matrix.values
    width /= a
    height /= d
    pattern_x = e / a
    pattern_y = f / d
    matrix = Matrix(e=x - node_x, f=y - node_y) @ matrix @ svg.stream.ctm
    pattern = svg.stream.add_pattern(-pattern_x, -pattern_y, width, height,
                                     width, height, matrix)
    group = pattern.add_group([0, 0, width, height])

    shading = group.add_shading()
    shading['ShadingType'] = shading_type
    shading['ColorSpace'] = '/DeviceRGB'
    shading['Domain'] = pydyf.Array([positions[0], positions[-1]])
    shading['Coords'] = pydyf.Array(coords)
    shading['Function'] = pydyf.Dictionary({
        'FunctionType':
        3,
        'Domain':
        pydyf.Array([positions[0], positions[-1]]),
        'Encode':
        pydyf.Array((len(colors) - 1) * [0, 1]),
        'Bounds':
        pydyf.Array(positions[1:-1]),
        'Functions':
        pydyf.Array([
            pydyf.Dictionary({
                'FunctionType':
                2,
                'Domain':
                pydyf.Array([positions[0], positions[-1]]),
                'C0':
                pydyf.Array(c0),
                'C1':
                pydyf.Array(c1),
                'N':
                n,
            }) for c0, c1, n in color_couples
        ]),
    })
    if spread not in ('repeat', 'reflect'):
        shading['Extend'] = pydyf.Array([b'true', b'true'])

    if any(alpha != 1 for alpha in alphas):
        alpha_stream = group.add_group(
            [0, 0, svg.concrete_width, svg.concrete_height])
        state = pydyf.Dictionary({
            'Type':
            '/ExtGState',
            'SMask':
            pydyf.Dictionary({
                'Type': '/Mask',
                'S': '/Luminosity',
                'G': alpha_stream,
            }),
            'ca':
            1,
            'AIS':
            'false',
        })
        group.set_state(state)

        alpha_shading = alpha_stream.add_shading()
        alpha_shading['ShadingType'] = shading_type
        alpha_shading['ColorSpace'] = '/DeviceGray'
        alpha_shading['Domain'] = pydyf.Array([positions[0], positions[-1]])
        alpha_shading['Coords'] = pydyf.Array(coords)
        alpha_shading['Function'] = pydyf.Dictionary({
            'FunctionType':
            3,
            'Domain':
            pydyf.Array([positions[0], positions[-1]]),
            'Encode':
            pydyf.Array((len(colors) - 1) * [0, 1]),
            'Bounds':
            pydyf.Array(positions[1:-1]),
            'Functions':
            pydyf.Array([
                pydyf.Dictionary({
                    'FunctionType': 2,
                    'Domain': pydyf.Array([0, 1]),
                    'C0': pydyf.Array([c0]),
                    'C1': pydyf.Array([c1]),
                    'N': 1,
                }) for c0, c1 in alpha_couples
            ]),
        })
        if spread not in ('repeat', 'reflect'):
            alpha_shading['Extend'] = pydyf.Array([b'true', b'true'])
        alpha_stream.stream = [f'/{alpha_shading.id} sh']

    group.shading(shading.id)
    pattern.draw_x_object(group.id)
    svg.stream.color_space('Pattern', stroke=stroke)
    svg.stream.set_color_special(pattern.id, stroke=stroke)
    return True