def test_symbol() -> None:
    symbol = Symbol('01b03c10-7334-4bd5-b2bc-942c18325d2b', Name('Sym name'),
                    Description(r'A multiline description.\n\nDescription'),
                    Keywords('my, keywords'), Author('Test'), Version('0.2'),
                    Created('2018-10-17T19:13:41Z'),
                    Category('d0618c29-0436-42da-a388-fdadf7b23892'))
    symbol.add_pin(
        SymbolPin('6da06b2b-7806-4e68-bd0c-e9f18eb2f9d8', Name('1'),
                  Position(5.08, 20.32), Rotation(180.0), Length(3.81)))
    polygon = Polygon('743dbf3d-98e8-46f0-9a32-00e00d0e811f',
                      Layer('sym_outlines'), Width(0.25), Fill(False),
                      GrabArea(True))
    polygon.add_vertex(Vertex(Position(-2.54, 22.86), Angle(0.0)))
    polygon.add_vertex(Vertex(Position(-2.54, -25.4), Angle(0.0)))
    polygon.add_vertex(Vertex(Position(-2.54, 22.86), Angle(0.0)))
    symbol.add_polygon(polygon)
    symbol.add_circle(
        Circle('b5599e68-ff6a-464b-9a40-c6ba8ef8daf5', Layer('sym_outlines'),
               Width(0.254), Fill(False), GrabArea(False), Diameter(1.27),
               Position(5.715, 0.0)))
    symbol.add_text(
        Text('b9c4aa19-0a46-400c-9c96-e8c3dfb8f83e', Layer('sym_names'),
             Value('{{NAME}}'), Align('center bottom'), Height(2.54),
             Position(0.0, 22.86), Rotation(0.0)))

    assert str(
        symbol) == """(librepcb_symbol 01b03c10-7334-4bd5-b2bc-942c18325d2b
def test_component() -> None:
    component = Component(
        '00c36da8-e22b-43a1-9a87-c3a67e863f49', Name('Generic Connector 1x27'),
        Description(r'A 1x27 soldered wire connector.\n\nNext line'),
        Keywords('connector, 1x27'), Author('Test R.'), Version('0.2'),
        Created('2018-10-17T19:13:41Z'), Deprecated(False),
        Category('d0618c29-0436-42da-a388-fdadf7b23892'), SchematicOnly(False),
        DefaultValue(''), Prefix('J'))
    component.add_signal(
        Signal('f46a4643-fc68-4593-a889-3d987bfe3544', Name('1'), Role.PASSIVE,
               Required(False), Negated(False), Clock(False), ForcedNet('')))

    gate = Gate('c1e4b542-a1b1-44d5-bec3-070776143a29',
                SymbolUUID('8f1a97f2-4cdf-43da-b38d-b3787c47b5ad'),
                Position(0.0, 0.0), Rotation(0.0), Required(True), Suffix(''))
    gate.add_pin_signal_map(
        PinSignalMap('0189aafc-f88a-4e65-8fb4-09a047a3e334',
                     SignalUUID('46f7e0e2-74a6-442b-9a5c-1bd4ea3da59c'),
                     TextDesignator.SYMBOL_PIN_NAME))
    variant = Variant('abeeeed0-6e9a-4fdc-bc2b-e2c5b06bbe3a', Norm.EMPTY,
                      Name('default'), Description(''), gate)

    component.add_variant(variant)

    assert str(component
               ) == """(librepcb_component 00c36da8-e22b-43a1-9a87-c3a67e863f49
Ejemplo n.º 3
0
def generate_dev(
    dirpath: str,
    diameter: float,
    height: float,
    pitch: float,
    lead_width: float,
    author: str,
    version: str,
    create_date: Optional[str],
) -> None:
    name = 'Capacitor Radial ⌀{}x{}/{}mm'.format(diameter, height, pitch)
    variant = get_variant(diameter, height, pitch, lead_width)

    def _uuid(identifier: str) -> str:
        return uuid('dev', variant, identifier)

    device = Device(
        uuid=_uuid('dev'),
        name=Name(name),
        description=Description(
            'Generic polarized radial electrolytic capacitor.\\n\\n' +
            'Diameter: {} mm\\n'.format(diameter) +
            'Height: {} mm\\n'.format(height) +
            'Lead Spacing: {} mm\\n'.format(pitch) +
            'Max. Lead Diameter: {} mm\\n\\n'.format(lead_width) +
            'Generated with {}'.format(generator)),
        keywords=Keywords(
            'electrolytic,capacitor,polarized,radial,c,cap,cpol'),
        author=Author(author),
        version=Version(version),
        created=Created(create_date or now()),
        deprecated=Deprecated(False),
        category=Category('c011cc6b-b762-498e-8494-d1994f3043cf'),
        component_uuid=ComponentUUID('c54375c5-7149-4ded-95c5-7462f7301ee7'),
        package_uuid=PackageUUID(uuid('pkg', variant, 'pkg')),
    )
    device.add_pad(
        ComponentPad(
            uuid=uuid('pkg', variant, 'pad-plus'),
            signal=SignalUUID('e010ecbb-6210-4da3-9270-ebd58656dbf0'),
        ))
    device.add_pad(
        ComponentPad(
            uuid=uuid('pkg', variant, 'pad-minus'),
            signal=SignalUUID('af3ffca8-0085-4edb-a775-fcb759f63411'),
        ))

    # write files
    pkg_dir_path = path.join(dirpath, device.uuid)
    if not (path.exists(pkg_dir_path) and path.isdir(pkg_dir_path)):
        makedirs(pkg_dir_path)
    with open(path.join(pkg_dir_path, '.librepcb-dev'), 'w') as f:
        f.write('0.1\n')
    with open(path.join(pkg_dir_path, 'device.lp'), 'w') as f:
        f.write(str(device))
        f.write('\n')
    print('Wrote device {}'.format(name))
def test_package() -> None:
    package = Package(
        '009e35ef-1f50-4bf3-ab58-11eb85bf5503',
        Name('Soldered Wire Connector 1x19 ⌀1.0mm'),
        Description(
            'A 1x19 soldered wire connector with 2.54mm pin spacing and 1.0mm drill holes.\n\nGenerated with librepcb-parts-generator (generate_connectors.py)'
        ), Keywords('connector, 1x19, d1.0, connector, soldering, generic'),
        Author('Danilo B.'), Version('0.1'), Created('2018-10-17T19:13:41Z'),
        Deprecated(False), Category('56a5773f-eeb4-4b39-8cb9-274f3da26f4f'))

    package.add_pad(
        PackagePad('5c4d39d3-35cc-4836-a082-693143ee9135', Name('1')))
    package.add_pad(
        PackagePad('6100dd55-d3b3-4139-9085-d5a75e783c37', Name('2')))

    package.add_footprint(create_footprint())
    assert str(
        package) == """(librepcb_package 009e35ef-1f50-4bf3-ab58-11eb85bf5503
def test_device() -> None:
    device = Device(
        '00652f30-9f89-4027-91f5-7bd684eee751',
        Name('Foo'),
        Description('Bar'),
        Keywords('foo, bar'),
        Author('J. Rando'),
        Version('0.1'),
        Created('2018-10-17T19:13:41Z'),
        Deprecated(False),
        Category('ade6d8ff-3c4f-4dac-a939-cc540c87c280'),
        ComponentUUID('bc911fcc-8b5c-4728-b596-d644797c55da'),
        PackageUUID('b4e92c64-18c4-44a6-aa39-d1be3e8c29bd'),
    )
    device.add_pad(
        ComponentPad('aec3f475-28c4-4508-ab4f-e1b618a0d77d',
                     SignalUUID('726fd1ce-a01b-4287-bb61-e3ff165a0644')))
    device.add_pad(
        ComponentPad('67a7b034-b30b-4644-b8d3-d7a99606efdc',
                     SignalUUID('9bccea5e-e23f-4b88-9de1-4be00dc0c12a')))
    assert str(
        device) == """(librepcb_device 00652f30-9f89-4027-91f5-7bd684eee751
from entities.component import (
    Clock, Component, DefaultValue, ForcedNet, Gate, Negated, Norm, PinSignalMap, Prefix, Required, Role, SchematicOnly,
    Signal, SignalUUID, Suffix, SymbolUUID, TextDesignator, Variant
)
from entities.device import ComponentPad, ComponentUUID, Device, PackageUUID
from entities.symbol import Pin as SymbolPin
from entities.symbol import Symbol

grid = 2.54  # Grid size in mm
width_regular = 10  # Symbol width in grid units
width_wide = 16  # Symbol width in grid units (used for symbols with very long pin names)
width_wide_threshold = 15  # Use wide symbol for pin names >= threshold characters long
line_width = 0.25  # Line width in mm
text_height = 2.5  # Name / value text height
generator = 'librepcb-parts-generator (generate_stm_mcu.py)'
keywords_stm32 = Keywords('stm32, stm, st, mcu, microcontroller, arm, cortex')
keywords_stm8 = Keywords('stm8, stm, st, mcu, microcontroller, 8bit')
author = Author('Danilo Bargen, John Eaton')
cmpcat = Category('22151601-c2d9-419a-87bc-266f9c7c3459')

# Initialize UUID cache
uuid_cache_file = 'uuid_cache_stm_mcu.csv'
uuid_cache = init_cache(uuid_cache_file)


def uuid(category: str, full_name: str, identifier: str) -> str:
    """
    Return a uuid for the specified item.

    Params:
        category:
Ejemplo n.º 7
0
def generate_pkg(
    dirpath: str,
    diameter: float,
    height: float,
    pitch: float,
    lead_width: float,
    author: str,
    version: str,
    create_date: Optional[str],
) -> None:
    # Name according IPC-7351 "Capacitor, Polarized Radial Diameter":
    # CAPPRD + Lead Spacing + W Lead Width + D Body Diameter + H Body Height
    name = 'CAPPRD{}W{}D{}H{}'.format(format_ipc_dimension(pitch),
                                      format_ipc_dimension(lead_width),
                                      format_ipc_dimension(diameter),
                                      format_ipc_dimension(height))
    variant = get_variant(diameter, height, pitch, lead_width)

    def _pkg_uuid(identifier: str) -> str:
        return uuid('pkg', variant, identifier)

    def _create_footprint(footprint_identifier: str, name: str) -> Footprint:
        def _fpt_uuid(identifier: str) -> str:
            return _pkg_uuid(footprint_identifier + '-' + identifier)

        drill = LEAD_WIDTH_TO_DRILL[lead_width]
        restring = min(
            (0.4 if diameter >= 6.0 else 0.3),  # preferred restring
            (pitch - drill - 0.25) / 2)  # minimum required restring
        pad_diameter = drill + (2 * restring)  # outer diameter of pad
        courtyard_diameter = diameter + (1.0 if diameter >= 10.0 else 0.8)

        def _generate_fill_polygon(identifier: str, layer: str) -> Polygon:
            polygon = Polygon(
                uuid=_fpt_uuid(identifier),
                layer=Layer(layer),
                width=Width(0.0),
                fill=Fill(True),
                grab_area=GrabArea(False),
            )
            if ((pitch - pad_diameter) < 0.6):
                # not enough space, use a simplified polygon
                vertices = [
                    (0.0, (diameter / 2) - 0.2, 0.0),
                    (0.0, (pad_diameter / 2) + 0.2, 0.0),
                    (pitch / 2, (pad_diameter / 2) + 0.2, -180.0),
                    (pitch / 2, -(pad_diameter / 2) - 0.2, 0.0),
                    (0.0, -(pad_diameter / 2) - 0.2, 0.0),
                    (0.0, -(diameter / 2) + 0.2, 180.0),
                    (0.0, (diameter / 2) - 0.2, 0.0),
                ]
            else:
                vertices = [
                    (0.0, (diameter / 2) - 0.2, 0.0),
                    (0.0, 0.0, 0.0),
                    ((pitch / 2) - (pad_diameter / 2) - 0.2, 0.0, -180.0),
                    ((pitch / 2) + (pad_diameter / 2) + 0.2, 0.0, -180.0),
                    ((pitch / 2) - (pad_diameter / 2) - 0.2, 0.0, 0.0),
                    (0.0, 0.0, 0.0),
                    (0.0, -(diameter / 2) + 0.2, 180.0),
                    (0.0, (diameter / 2) - 0.2, 0.0),
                ]
            for vertex in vertices:
                polygon.add_vertex(
                    Vertex(Position(vertex[0], vertex[1]), Angle(vertex[2])))
            return polygon

        footprint = Footprint(
            uuid=_fpt_uuid('footprint'),
            name=Name(name),
            description=Description(''),
        )
        footprint.add_pad(
            FootprintPad(
                uuid=_pkg_uuid('pad-plus'),
                side=Side.THT,
                shape=Shape.RECT,
                position=Position(-pitch / 2, 0),
                rotation=Rotation(0),
                size=Size(pad_diameter, pad_diameter),
                drill=Drill(drill),
            ))
        footprint.add_pad(
            FootprintPad(
                uuid=_pkg_uuid('pad-minus'),
                side=Side.THT,
                shape=Shape.ROUND,
                position=Position(pitch / 2, 0),
                rotation=Rotation(0),
                size=Size(pad_diameter, pad_diameter),
                drill=Drill(drill),
            ))

        # placement
        footprint.add_circle(
            Circle(
                uuid=_fpt_uuid('circle-placement'),
                layer=Layer('top_placement'),
                width=Width(0.2),
                fill=Fill(False),
                grab_area=GrabArea(False),
                diameter=Diameter(diameter + 0.2),
                position=Position(0.0, 0.0),
            ))
        footprint.add_polygon(
            _generate_fill_polygon(
                identifier='polygon-placement-fill',
                layer='top_placement',
            ))

        # documentation
        footprint.add_circle(
            Circle(
                uuid=_fpt_uuid('circle-documentation'),
                layer=Layer('top_documentation'),
                width=Width(0.2),
                fill=Fill(False),
                grab_area=GrabArea(False),
                diameter=Diameter(diameter - 0.2),
                position=Position(0.0, 0.0),
            ))
        footprint.add_polygon(
            _generate_fill_polygon(
                identifier='polygon-documentation-fill',
                layer='top_documentation',
            ))

        # courtyard
        footprint.add_circle(
            Circle(
                uuid=_fpt_uuid('circle-courtyard'),
                layer=Layer('top_courtyard'),
                width=Width(0.2),
                fill=Fill(False),
                grab_area=GrabArea(False),
                diameter=Diameter(courtyard_diameter),
                position=Position(0.0, 0.0),
            ))

        # texts
        footprint.add_text(
            StrokeText(
                uuid=_fpt_uuid('text-name'),
                layer=Layer('top_names'),
                height=Height(1.0),
                stroke_width=StrokeWidth(0.2),
                letter_spacing=LetterSpacing.AUTO,
                line_spacing=LineSpacing.AUTO,
                align=Align('center bottom'),
                position=Position(0.0, (diameter / 2) + 0.8),
                rotation=Rotation(0.0),
                auto_rotate=AutoRotate(True),
                mirror=Mirror(False),
                value=Value('{{NAME}}'),
            ))
        footprint.add_text(
            StrokeText(
                uuid=_fpt_uuid('text-value'),
                layer=Layer('top_values'),
                height=Height(1.0),
                stroke_width=StrokeWidth(0.2),
                letter_spacing=LetterSpacing.AUTO,
                line_spacing=LineSpacing.AUTO,
                align=Align('center top'),
                position=Position(0.0, -(diameter / 2) - 0.8),
                rotation=Rotation(0.0),
                auto_rotate=AutoRotate(True),
                mirror=Mirror(False),
                value=Value('{{VALUE}}'),
            ))
        return footprint

    # package
    package = Package(
        uuid=_pkg_uuid('pkg'),
        name=Name(name),
        description=Description(
            'Polarized radial electrolytic capacitor.\\n\\n' +
            'Diameter: {} mm\\n'.format(diameter) +
            'Height: {} mm\\n'.format(height) +
            'Lead Spacing: {} mm\\n'.format(pitch) +
            'Max. Lead Diameter: {} mm\\n\\n'.format(lead_width) +
            'Generated with {}'.format(generator)),
        keywords=Keywords(
            'electrolytic,capacitor,polarized,radial,c,cap,cpol'),
        author=Author(author),
        version=Version(version),
        created=Created(create_date or now()),
        deprecated=Deprecated(False),
        category=Category('ee75e31d-f231-41d9-8a3b-bea5114f41e3'),
    )
    package.add_pad(PackagePad(uuid=_pkg_uuid('pad-plus'), name=Name('+')))
    package.add_pad(PackagePad(uuid=_pkg_uuid('pad-minus'), name=Name('-')))
    package.add_footprint(
        _create_footprint(
            footprint_identifier='default',
            name='default',
        ))

    # write files
    pkg_dir_path = path.join(dirpath, package.uuid)
    if not (path.exists(pkg_dir_path) and path.isdir(pkg_dir_path)):
        makedirs(pkg_dir_path)
    with open(path.join(pkg_dir_path, '.librepcb-pkg'), 'w') as f:
        f.write('0.1\n')
    with open(path.join(pkg_dir_path, 'package.lp'), 'w') as f:
        f.write(str(package))
        f.write('\n')
    print('Wrote package {}'.format(name))
def generate_cmp(
    dirpath: str,
    author: str,
    name: str,
    name_lower: str,
    kind: str,
    cmpcat: str,
    keywords: str,
    default_value: str,
    rows: int,
    min_pads: int,
    max_pads: int,
    version: str,
    create_date: Optional[str],
) -> None:
    category = 'cmp'
    assert rows in [1, 2]
    for i in range(min_pads, max_pads + 1, rows):
        per_row = i // rows
        variant = '{}x{}'.format(rows, per_row)

        def _uuid(identifier: str) -> str:
            return uuid(category, kind, variant, identifier)

        uuid_cmp = _uuid('cmp')
        uuid_pins = [
            uuid('sym', kind, variant, 'pin-{}'.format(p)) for p in range(i)
        ]
        uuid_signals = [_uuid('signal-{}'.format(p)) for p in range(i)]
        uuid_variant = _uuid('variant-default')
        uuid_gate = _uuid('gate-default')
        uuid_symbol = uuid('sym', kind, variant, 'sym')

        # General info
        component = Component(
            uuid_cmp,
            Name('{} {}x{:02d}'.format(name, rows, per_row)),
            Description('A {}x{} {}.\\n\\n'
                        'Generated with {}'.format(rows, per_row, name_lower,
                                                   generator)),
            Keywords('connector, {}x{}, {}'.format(rows, per_row, keywords)),
            Author(author),
            Version(version),
            Created(create_date or now()),
            Deprecated(False),
            Category(cmpcat),
            SchematicOnly(False),
            DefaultValue(default_value),
            Prefix('J'),
        )

        for p in range(1, i + 1):
            component.add_signal(
                Signal(
                    uuid_signals[p - 1],
                    Name(str(p)),
                    Role.PASSIVE,
                    Required(False),
                    Negated(False),
                    Clock(False),
                    ForcedNet(''),
                ))

        gate = Gate(
            uuid_gate,
            SymbolUUID(uuid_symbol),
            Position(0.0, 0.0),
            Rotation(0.0),
            Required(True),
            Suffix(''),
        )
        for p in range(1, i + 1):
            gate.add_pin_signal_map(
                PinSignalMap(
                    uuid_pins[p - 1],
                    SignalUUID(uuid_signals[p - 1]),
                    TextDesignator.SYMBOL_PIN_NAME,
                ))

        component.add_variant(
            Variant(uuid_variant, Norm.EMPTY, Name('default'), Description(''),
                    gate))

        component.serialize(dirpath)

        print('{}x{} {}: Wrote component {}'.format(rows, per_row, kind,
                                                    uuid_cmp))
def generate_sym(
    dirpath: str,
    author: str,
    name: str,
    name_lower: str,
    kind: str,
    cmpcat: str,
    keywords: str,
    rows: int,
    min_pads: int,
    max_pads: int,
    version: str,
    create_date: Optional[str],
) -> None:
    category = 'sym'
    assert rows in [1, 2]
    for i in range(min_pads, max_pads + 1, rows):
        per_row = i // rows
        w = width * rows  # Make double-row symbols wider!

        variant = '{}x{}'.format(rows, per_row)

        def _uuid(identifier: str) -> str:
            return uuid(category, kind, variant, identifier)

        uuid_sym = _uuid('sym')
        uuid_pins = [_uuid('pin-{}'.format(p)) for p in range(i)]
        uuid_polygon = _uuid('polygon-contour')
        uuid_decoration = _uuid('polygon-decoration')
        uuid_text_name = _uuid('text-name')
        uuid_text_value = _uuid('text-value')

        # General info
        symbol = Symbol(
            uuid_sym,
            Name('{} {}x{:02d}'.format(name, rows, per_row)),
            Description('A {}x{} {}.\\n\\n'
                        'Generated with {}'.format(rows, per_row, name_lower,
                                                   generator)),
            Keywords('connector, {}x{}, {}'.format(rows, per_row, keywords)),
            Author(author),
            Version(version),
            Created(create_date or now()),
            Category(cmpcat),
        )

        for p in range(1, i + 1):
            x_sign = 1 if (p % rows == 0) else -1
            pin = SymbolPin(
                uuid_pins[p - 1], Name(str(p)),
                Position((w + 2.54) * x_sign, get_y(p, i, rows, spacing,
                                                    True)),
                Rotation(180.0 if p % rows == 0 else 0), Length(3.81))
            symbol.add_pin(pin)

        # Polygons
        y_max, y_min = get_rectangle_bounds(i, rows, spacing, spacing, True)
        polygon = Polygon(uuid_polygon, Layer('sym_outlines'),
                          Width(line_width), Fill(False), GrabArea(True))
        polygon.add_vertex(Vertex(Position(-w, y_max), Angle(0.0)))
        polygon.add_vertex(Vertex(Position(w, y_max), Angle(0.0)))
        polygon.add_vertex(Vertex(Position(w, y_min), Angle(0.0)))
        polygon.add_vertex(Vertex(Position(-w, y_min), Angle(0.0)))
        polygon.add_vertex(Vertex(Position(-w, y_max), Angle(0.0)))
        symbol.add_polygon(polygon)

        # Decorations
        if kind == KIND_HEADER:
            # Headers: Small rectangle
            for p in range(1, i + 1):
                x_sign = 1 if (p % rows == 0) else -1
                y = get_y(p, i, rows, spacing, True)
                dx = spacing / 8 * 1.5 * x_sign
                dy = spacing / 8 / 1.5
                x_offset = x_sign * (w - 1.27)
                polygon = Polygon(uuid_decoration, Layer('sym_outlines'),
                                  Width(line_width), Fill(True),
                                  GrabArea(True))
                polygon.add_vertex(
                    Vertex(Position(x_offset - dx, y + dy), Angle(0.0)))
                polygon.add_vertex(
                    Vertex(Position(x_offset + dx, y + dy), Angle(0.0)))
                polygon.add_vertex(
                    Vertex(Position(x_offset + dx, y - dy), Angle(0.0)))
                polygon.add_vertex(
                    Vertex(Position(x_offset - dx, y - dy), Angle(0.0)))
                polygon.add_vertex(
                    Vertex(Position(x_offset - dx, y + dy), Angle(0.0)))
                symbol.add_polygon(polygon)
        elif kind == KIND_SOCKET:
            # Sockets: Small semicircle
            for p in range(1, i + 1):
                x_sign = 1 if (p % rows == 0) else -1
                y = get_y(p, i, rows, spacing, True)
                dy = spacing / 4 * 0.75
                x_offset = x_sign * (w - 1.27 - dy * 0.75)
                polygon = Polygon(uuid_decoration, Layer('sym_outlines'),
                                  Width(line_width * 0.75), Fill(False),
                                  GrabArea(False))
                polygon.add_vertex(
                    Vertex(Position(x_offset, y - dy), Angle(x_sign * 135.0)))
                polygon.add_vertex(
                    Vertex(Position(x_offset, y + dy), Angle(0.0)))
                symbol.add_polygon(polygon)

        # Text
        y_max, y_min = get_rectangle_bounds(i, rows, spacing, spacing, True)
        text = Text(uuid_text_name, Layer('sym_names'), Value('{{NAME}}'),
                    Align('center bottom'), Height(sym_text_height),
                    Position(0.0, y_max), Rotation(0.0))
        symbol.add_text(text)

        text = Text(uuid_text_value, Layer('sym_values'), Value('{{VALUE}}'),
                    Align('center top'), Height(sym_text_height),
                    Position(0.0, y_min), Rotation(0.0))
        symbol.add_text(text)

        sym_dir_path = path.join(dirpath, uuid_sym)
        if not (path.exists(sym_dir_path) and path.isdir(sym_dir_path)):
            makedirs(sym_dir_path)
        with open(path.join(sym_dir_path, '.librepcb-sym'), 'w') as f:
            f.write('0.1\n')
        with open(path.join(sym_dir_path, 'symbol.lp'), 'w') as f:
            f.write(str(symbol))
            f.write('\n')

        print('{}x{} {}: Wrote symbol {}'.format(rows, per_row, kind,
                                                 uuid_sym))