Supported File Formats

SurfaceTopography supports reading surface topography data from a wide variety of file formats commonly used by commercial profilometers, AFMs, and other surface measurement instruments.

File Format Table

Format Name

Extensions

Description

Alicona Imaging AL3D

.al3d

AL3D format of Alicona Imaging optical 3D measurement systems

BCR-STM

.bcr, .bcrf

BCR-STM and BCRF file formats for scanning tunneling microscopy

Bruker/Veeco/DI Nanoscope

.spm, .001-.005

Digital Instruments, Veeco, and Bruker Dimension AFM formats

Bruker Dektak OPDx

.opdx

File format of the Bruker Dektak XT series stylus profilometer

Bruker Wyko OPD

.opd

Files generated by Vision software of Bruker Wyko white-light interferometers

Digital Metrology OmniSurf3D

.os3d

OmniSurf3D format from Digital Metrology

Digital Surf Mountains MNT

.mnt

Digital Surf Mountains OLE-based format with compressed height data (see Digital Surf Mountains MNT Format)

Digital Surf SUR

.sur

Digital Surf SUR data files

Gwyddion

.gwy

Native file format of the open-source SPM visualization software Gwyddion

Hierarchical Data Format (HDF5)

.h5

HDF5 files with 2D arrays (e.g., contact mechanics challenge data)

Igor Binary Wave

.ibw

Igor binary wave container format (WaveMetrics Igor Pro)

ISO 25178-71 SDF

.sdf

ISO 25178-71 Surface Data File format (ASCII and binary variants)

JPK Image Scan

.jpk

TIFF-based file format of JPK instruments (now Bruker)

Keyence VK

.vk3, .vk4, .vk6, .vk7

VK3/VK4/VK6/VK7 formats of Keyence laser confocal microscopes

Keyence ZON

.zon

ZON files from some Keyence instruments

KLA Zeta

.zmg

KLA Zeta ZMG profilometry data files

MATLAB

.mat

MATLAB workspace files containing topography data

Microprof FRT

.frt

MicroProf FRT profilometry data

Mitutoyo SurfTest

.xlsx

Excel spreadsheets from Mitutoyo SurfTest instruments

Molecular Imaging (MI)

.mi

Agilent Technologies (Molecular Imaging) AFM format

Nanofocus

.nms

Nanofocus NMS profilometry data files

NanoSurf easyScan

.ezd, .nid

NanoSurf easyScan data files

Nanomeasuring Machine (NMM)

.zip

ZIP-packaged nanomeasuring machine files

NASA SRTM

.hgt

NASA Shuttle Radar Topography Mission elevation data

NetCDF

.nc

Network Common Data Format (classic and HDF5-based NetCDF4)

NumPy Array

.npy

NumPy binary array format

Olympus LEXT

.lext

TIFF-based format of Olympus LEXT confocal microscopes

Olympus OIR

.oir

Olympus OIR data files

Olympus Packed OIR

.poir

ZIP-packaged Olympus OIR files

Park Systems TIFF

.tiff, .tif

TIFF-based format of Park Systems AFM instruments

Plain Text (ASCII)

.txt, .asc, .dat

Plain text files with optional headers

Plain Text (XYZ)

.xyz, .hfm, .csv

Coordinate data as (x, y, z) tuples

Sensofar PLU

.plu, .apx

Sensofar SPM file format

Sensofar PLUX

.plux

Sensofar XML-based SPM file format

TrueMap

.tmd

TrueMap TMD profilometry data files

WSxM

.cur, .stp, .tom, .top

WSxM SPM data files

X3P

.x3p

ISO 5436-2 XML 3D surface profile container format

Zygo DATX

.datx

Zygo DATX HDF5-based format

Zygo MetroPro

.dat

Zygo MetroPro data files

Container Formats

In addition to individual topography files, SurfaceTopography can read container formats that bundle multiple topographies:

Format Name

Extensions

Description

contact.engineering

.zip

Digital surface twin containers from contact.engineering

Keyence ZAG

.zag

Keyence ZAG container format

Basic Usage

from SurfaceTopography import open_topography, read_topography

# Auto-detect format and open file
reader = open_topography("measurement.vk4")
topography = reader.topography()

# Or read directly
topography = read_topography("measurement.vk4")

For formats that don’t store physical sizes or units (e.g., NPY, HDF5), you must provide them:

topography = read_topography("data.npy", physical_sizes=(10.0, 10.0), unit="um")

Working with Channels

Many file formats support multiple data channels (e.g., height, phase, amplitude error). You can inspect available channels and select which one to load.

Inspecting Channels

from SurfaceTopography import open_topography

reader = open_topography("afm_scan.ibw")

# List all channels
for ch in reader.channels:
    print(f"  {ch.name}: {ch.channel_id} (height={ch.is_height_channel})")

# Access only height channels (backwards compatible)
for ch in reader.height_channels:
    print(f"  Height channel: {ch.name}")

Channel Selection Methods

There are three ways to select which channel to load:

# Method 1: By channel index (default behavior)
topo = reader.topography(channel_index=0)

# Method 2: By stable channel ID (recommended for database storage)
topo = reader.topography(channel_id="Height")

# Method 3: By height channel index (backwards compatible, only counts height channels)
topo = reader.topography(height_channel_index=0)

Channel Properties

Each channel (ChannelInfo) has the following properties:

  • name - Human-readable channel name from the file

  • channel_id - Stable unique identifier (e.g., “Height”, “Phase#2” for duplicates)

  • is_height_channel - True if channel contains height/topography data

  • height_index - Index among height channels only (None for non-height channels)

  • data_kind - Type of data (HEIGHT, VOLTAGE, PHASE, AMPLITUDE, etc.)

  • dim - Dimensionality (1 for line scans, 2 for maps)

  • nb_grid_pts - Number of grid points

  • physical_sizes - Physical dimensions

  • unit - Unit of measurement

Stable Channel Identification

For applications that store channel references in databases, use channel_id instead of channel_index. The channel_id is:

  • Stable: Remains the same across different reads of the same file

  • Order-independent: Doesn’t depend on the internal order channels appear

  • Unique: Automatically disambiguated for duplicate names (e.g., “Height#1”, “Height#2”)

Example for database storage:

# When saving to database, store the channel_id
channel_to_store = reader.channels[0].channel_id  # e.g., "Height"

# Later, when loading from database
topo = reader.topography(channel_id=channel_to_store)

Migrating from Height Index to Channel ID

For databases that previously stored height_channel_index values, utility functions are provided to convert between the old and new systems:

from SurfaceTopography import open_topography

reader = open_topography("scan.ibw")

# Convert old height index to new channel_id
old_index = 0  # stored in database
new_id = reader.height_index_to_channel_id(old_index)
# new_id is now something like "Height" or "ZSensor"

# Convert back if needed (only works for height channels)
recovered_index = reader.channel_id_to_height_index(new_id)
assert recovered_index == old_index

Migration script example:

from SurfaceTopography import open_topography

def migrate_database_entry(file_path, old_height_index):
    """Migrate a database entry from height_index to channel_id."""
    reader = open_topography(file_path)
    new_channel_id = reader.height_index_to_channel_id(old_height_index)
    return new_channel_id

# Example usage
# old_entry = {"file": "scan.ibw", "channel": 0}
# new_entry = {"file": "scan.ibw", "channel_id": migrate_database_entry("scan.ibw", 0)}

Notes

  • File format is auto-detected from file content (magic bytes) when possible

  • Some formats support multiple channels - use reader.channels to inspect

  • Most readers support both file paths and file-like objects

  • Some readers support MPI-parallel reading for large datasets