Skip to main content

GDSII format reader/writer

Project description

klamath README

klamath is a Python module for reading and writing to the GDSII file format.

The goal is to keep this library simple:

  • Map data types directly wherever possible.
    • Presents an accurate representation of what is saved to the file.
    • Avoids excess copies / allocations for speed.
    • No "automatic" error checking, except when casting datatypes. If data integrity checks are provided at all, they must be explicitly run by the caller.
  • Low-level functionality is first-class.
    • Meant for use-cases where the caller wants to read or write individual GDS records.
    • Offers complete control over the written file.
  • Opinionated and limited high-level functionality.
    • Discards or ignores rarely-encountered data types.
    • Keeps functions simple and reusable.
    • Only de/encodes the file format, doesn't provide tools to modify the data itself.
    • Still requires explicit values for most fields.
  • No compilation
    • Uses numpy for speed, since it's commonly available / pre-built.
    • Building this library should not require a compiler.

klamath was built to provide a fast and versatile GDS interface for masque, which provides higher-level tools for working with hierarchical design data and supports multiple file formats.


  • gdspy
    • Provides abstractions and methods for working with design data outside of the I/O process (e.g. polygon clipping).
    • Requires compilation (C++) to build from source.
    • Focused on high-level API
  • python-gdsii
    • Pure-python implementation. Can easily be altered to use numpy for speed, but is limited by object allocation overhead.
    • Focused on high-level API




  • python >= 3.7 (written and tested with 3.8)
  • numpy

Install with pip:

pip3 install klamath

Alternatively, install from git

pip3 install git+



Filter which polygons are read based on layer:

import io
import klamath
from klamath import records
from klamath.record import Record

def read_polygons(stream, filter_layer_tuple=(4, 5)):
    Given a stream positioned at the start of a record,
     return the vertices of all BOUNDARY records which match
     the provided `filter_layer_tuple`, up to the next
     ENDSTR record.
    polys = []
    while True:
        size, tag = Record.read_header(stream), io.SEEK_CUR)      # skip to next header

        if tag == records.ENDEL.tag:
            break                           # If ENDEL, we are done

        if tag != records.BOUNDARY.tag:
            continue                        # Skip until we find a BOUNDARY

        layer = records.LAYER.skip_and_read(stream)[0]  # skip to LAYER
        dtype =[0]

        if (layer, dtype) != filter_layer_tuple:
            continue                        # Skip reading XY unless layer matches

        xy =, 2)
    return polys


Write an example GDS file:

import klamath
from klamath.elements import Boundary, Text, Path, Reference

stream = open('example.gds', 'wb')

header = klamath.library.FileHeader(
                meters_per_db_unit=1e-9,      # 1 nm DB unit
                user_units_per_db_unit=1e-3)  # 1 um (1000nm) display unit

elements_A = [
    Boundary(layer=(4, 18),
             xy=[[0, 0], [10, 0], [10, 20], [0, 20], [0, 0]],
             properties={1: b'prop1string', 2: b'some other string'}),
    Text(layer=(5, 5),
         xy=[[5, 10]],
         string=b'center position',
         properties={},        # Remaining args are set to default values
         presentation=0,       #   and will be omitted when writing
    Path(layer=(4, 20),
         xy=[[0, 0], [10, 10], [0, 20]],
         extension=(0, 0),     # ignored since path_type=0
klamath.library.write_struct(stream, name=b'my_struct', elements=elements_A)

elements_top = [
              xy=[[30, 30]],
              colrow=None,   # not an array
              colrow=(3, 2),                    # 3x2 array at (0, 50)
              xy=[[0, 50], [60, 50], [30, 50]], #   with basis vectors
              angle_deg=30,                     #   [20, 0] and [0, 30]
klamath.library.write_struct(stream, name=b'top', elements=elements_top)

klamath.records.ENDLIB.write(stream, None)

Read back the file:

import klamath

stream = open('example.gds', 'rb')
header =

structs = {}

struct = klamath.library.try_read_struct(stream)
while struct is not None:
    name, elements = struct
    structs[name] = elements
    struct = klamath.library.try_read_struct(stream)



Read back a single struct by name:

import klamath

stream = open('example.gds', 'rb')

header =
struct_positions = klamath.library.scan_structs(stream)[b'my_struct'])
elements_A = klamath.library.try_read_struct(stream)



Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for klamath, version 1.1
Filename, size File type Python version Upload date Hashes
Filename, size klamath-1.1-py3-none-any.whl (28.9 kB) File type Wheel Python version py3 Upload date Hashes View
Filename, size klamath-1.1.tar.gz (16.8 kB) File type Source Python version None Upload date Hashes View

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page