An open-source CGM (Computer Graphics Metafile) parser and CGM→SVG converter.
CGM is the vector format that aerospace, defence, and automotive technical publications have standardised on for three decades — it is what S1000D and ATA iSpec 2200 illustrations are authored in. The open-source tooling for it has not kept up: RALCGM is unmaintained, and ImageMagick and Inkscape have effectively no usable CGM support.
OpenCGM is a modern, actively developed implementation: a complete ISO/IEC 8632 parser, a Skia-backed renderer, and an SVG emitter with profile support for WebCGM 2.1 and S1000D.
- Parses CGM binary and clear-text encodings per ISO/IEC 8632-3:1999 and ISO/IEC 8632-4:1999
- Converts CGM to SVG with WebCGM 2.1 and S1000D output profiles
- Preserves application structure (APS) — layers, names, screentips, link URIs, and region hotspots survive the conversion
- Handles the parts that usually break: NURBS approximation, cell arrays, tile rasters (JPEG / PNG / bitmap / CCITT G4), pattern and hatch geometry, and font substitution with ACI font normalisation
- Ships a C API for embedding, a CLI, and a validation tool
- Round-trips CGM → CGM as well as converting
Requires CMake 3.15+, a C++17 compiler, and optionally
Skia for the native renderer (consumed via vcpkg; see
vcpkg.json, and configure with -DENABLE_SKIA_RENDERER=ON).
cmake -B build
cmake --build buildBinaries land in build/bin: opencgm_cli, cgm_validate, and the
opencgm shared library.
opencgm_cli --profile s1000d input.cgm output.svgCommon options:
--profile <s1000d|webcgm|compat>— output profile (s1000dis the default)--font-map <file>— JSON font map describing CGM font substitutions and optional embedded WOFF2 resources--text-as-path/--text-as-path-threshold <value>— outline text for pixel-exact verification--validate-geometry— enforce viewBox/viewcontext consistency; tune with--geometry-tolerance <value>(default: 0.01 user units)--geometry-log/--raster-log— emit diagnostics to stderr
opencgm_cli --help lists every flag.
#include <opencgm/cgm_file.h>
auto cgmFile = cgm::BinaryCGMFile("input.cgm");
for (const auto& command : cgmFile.getCommands()) {
// inspect or transform
}
cgmFile.writeFile("output.cgm");A stable C API is available in include/opencgm/c_api.h for binding from other
languages.
| Path | Contents |
|---|---|
src/core/, src/classes/ |
CGM file handling and data structures |
src/commands/ |
CGM command implementations |
src/import/, src/export/ |
Binary and clear-text parsing and writing |
src/svg/ |
SVG emission and profile handling |
src/skia/ |
Skia renderer |
src/nurbs/, src/xcf/ |
NURBS approximation, XCF support |
src/validation/ |
Profile and geometry validation |
include/opencgm/ |
Public headers and C API |
tests/ |
Unit tests and corpus-driven conversion tests |
cmake -B build -DBUILD_TESTS=ON
cmake --build build
ctest --test-dir buildThat runs green on a fresh clone. Sample corpora are not vendored — the WebCGM 2.1 Conformance Test Suite and the S1000D Bike Data Set are third-party data under their own terms — so tests needing a corpus skip until you fetch one:
python scripts/fetch-testdata.py
export OPENCGM_SAMPLES_DIR=$PWD/testdataThe WebCGM suite downloads automatically from OASIS with a pinned checksum and activates 78 further tests. The S1000D Bike Data Set is distributed through the S1000D users' portal and must be installed by hand; the script prints instructions.
Every file in the WebCGM 2.1 Conformance Test Suite (353 CGMs) converts successfully under all three output profiles, producing well-formed SVG:
| Profile | Converted | Failures |
|---|---|---|
webcgm |
353/353 (100%) | 0 |
s1000d |
353/353 (100%) | 0 |
compat |
353/353 (100%) | 0 |
Full results, including how much the profiles actually diverge from one
another, are in docs/corpus-report.md. The report is
generated by scripts/corpus-report.py and is reproducible from a clean
checkout.
This measures conversion coverage and SVG well-formedness, not visual fidelity, and is not a WebCGM conformance certification.
The WebCGM static test suite ships its methodology in machine-readable form:
static10/webCGMsuite.xml lists the official operator checkpoints for each of
its 232 rendering test cases. scripts/conformance.py runs them:
| Checkpoints | |
|---|---|
| total | 912 |
| decided mechanically | 438 (48%) |
| passed | 438 |
| failed | 0 |
| require an operator | 474 (52%) |
Full results by CGM category are in
docs/conformance-report.md. Checkpoints that
describe what a person should see are written to an operator worksheet
(--worksheet) pairing each reference image with this converter's rendering.
This is not a conformance certification, and OpenCGM does not claim WebCGM
conformance: that is defined for viewers, and the suite's 20tests,
21tests and dynamic10 modules almost entirely exercise a viewer's DOM and
XCF APIs and link navigation, which a converter has no part in. The static10
module is the part that tests rendering, and it is what is measured.
scripts/visual-compare.py additionally rasterises converted output and ranks
cases by divergence from the reference images
(docs/visual-comparison.md) as a regression
screen; it has already surfaced real gaps.
See CONTRIBUTING.md. The most useful contributions are usually narrow: a CGM file that renders wrong, plus a test pinning the correct behaviour.
Licensed under the Apache License 2.0.
OpenCGM is a C++ port of the codessentials.CGM C# library by Toni Wenzel, used under the MIT License. See NOTICE and THIRD-PARTY-NOTICES.md for full attribution.
Reforge, a commercial desktop application built on this engine — batch conversion, folder monitoring, a validation UI, and hotspot export — is available separately. OpenCGM itself is and remains Apache-2.0.