A Python-based GUI application for viewing and converting vintage vector graphics files with graphical rendering support. Supports both CGM (Computer Graphics Metafile) and WMF (Windows Metafile) formats. Includes an interactive Tkinter-based GUI viewer and command-line conversion tools.
Features:
- CGM support with HiJaak 2 MIL-D-28003 extensions
- WMF support for Windows 3.x metafiles
- Interactive GUI with arrow key navigation
- PNG export for both formats
- SVG export for CGM files
-
vvi_viewer.py- Interactive GUI viewer with Tkinter- Real-time rendering of CGM and WMF files using PIL/Pillow
- Arrow key navigation through directories
- PNG export for both CGM and WMF
- SVG export for CGM files
- Binary parsers for CGM (with HiJaak extensions) and WMF
-
cgm_to_svg.py- Command-line CGM to SVG converter- Batch conversion support
- Configurable output dimensions
- Uses
cgm_svg_renderer.pyfor vector output
-
cgm_svg_renderer.py- SVG rendering engine- Converts CGM primitives to SVG elements
- Handles coordinate transformation
- Color table management
-
wmf_parser.py- WMF parser and renderer- Binary WMF parser for Windows Metafile format
- PIL-based rendering engine
- Supports placeable and standard WMF headers
- GDI object management
cgm_fileformat.md- Detailed CGM format specificationwmf_fileformat.md- Detailed WMF format specificationtest_features.sh- Automated testing scriptSample_Files/- Sample vector graphics (OWL1.CGM, BUTRFLY.WMF, sample.wmf)CLAUDE.md- Development notes and architecture guideFEATURES.md- Feature list and implementation status
-
Multi-Format Support: Renders both CGM and WMF vector graphics
-
CGM Support:
- Polylines and polygons
- Rectangles and circles
- Text elements
- Color and line width attributes
- HiJaak vendor extensions (Element 23)
- Binary encoding (ISO/IEC 8632)
-
WMF Support:
- Polylines and polygons
- Rectangles and ellipses
- Lines (LINETO/MOVETO)
- Text elements
- GDI objects (pens, brushes)
- Placeable metafile headers
- Windows 3.x era metafiles
-
Arrow Key Navigation: Browse through vector files in a directory
- ← Previous file
- → Next file
- File counter shows position (e.g., "file.wmf (2/5)")
- Works with mixed CGM/WMF directories
-
Export Options:
- Save as PNG - High-quality bitmap export (CGM and WMF)
- Save as SVG - Scalable vector graphics (CGM only)
-
Browse Function: Easy file selection with dialog supporting both formats
- Python 3.6+ (Python 3.7+ recommended)
- tkinter - GUI framework (uses TCL/Tk)
- Usually included with Python standard installations
- Required by
vvi_viewer.py
- Pillow - Python Imaging Library for raster graphics
- Required by
vvi_viewer.py
- Required by
Install Python dependencies:
pip install -r requirements.txtOr manually:
pip install pillowMost Python installations include tkinter by default. If you encounter ModuleNotFoundError: No module named 'tkinter':
Ubuntu/Debian:
sudo apt-get install python3-tkFedora/RHEL:
sudo dnf install python3-tkintermacOS:
- Usually included with Python from python.org
- Homebrew:
brew install python-tk
Windows:
- Reinstall Python from python.org with "tcl/tk and IDLE" option checked
-
Clone or download this repository
-
Ensure Python 3.6+ is installed:
python --version
-
Install dependencies:
pip install -r requirements.txt
-
Verify tkinter is available:
python -c "import tkinter; print('tkinter OK')"
Launch the interactive viewer:
python vvi_viewer.pyControls:
- Click "Browse Vector File" to select a file (.cgm or .wmf)
- View rendered graphics in the main window
- Use arrow keys for navigation:
←Previous file in directory→Next file in directory- Works with mixed CGM/WMF directories
- Export options:
- "Save as PNG" - Raster image export (both CGM and WMF)
- "Save as SVG" - Vector graphics export (CGM only)
GUI Features:
- Automatic format detection (CGM or WMF)
- File counter shows position (e.g., "OWL1.CGM (2/5)")
- Status bar shows file format and rendering progress
- Scrollable canvas for large graphics
- Automatic directory file list management
Convert a single file to SVG:
python cgm_to_svg.py input.cgm output.svgConvert with custom dimensions (width x height in pixels):
python cgm_to_svg.py input.cgm output.svg 1200 900Parameters:
input.cgm- Source CGM file pathoutput.svg- Destination SVG file pathwidth(optional) - SVG width in pixels (default: 800)height(optional) - SVG height in pixels (default: 600)
Bash/Linux/macOS:
# Convert all .cgm files in current directory
for f in *.cgm; do
python cgm_to_svg.py "$f" "${f%.cgm}.svg"
done
# Convert all .CGM files (uppercase extension)
for f in *.CGM; do
python cgm_to_svg.py "$f" "${f%.CGM}.svg"
doneWindows PowerShell:
Get-ChildItem *.cgm | ForEach-Object {
python cgm_to_svg.py $_.Name ($_.BaseName + ".svg")
}Windows Command Prompt:
for %f in (*.cgm) do python cgm_to_svg.py "%f" "%~nf.svg"Delimiter Elements (Class 0):
- BEGIN METAFILE, END METAFILE, BEGIN PICTURE, BEGIN PICTURE BODY, END PICTURE
Metafile Descriptor Elements (Class 1):
- METAFILE VERSION, METAFILE DESCRIPTION, VDC TYPE, INTEGER PRECISION, COLOUR PRECISION
Picture Descriptor Elements (Class 2):
- VDC EXTENT, BACKGROUND COLOUR, COLOUR SELECTION MODE (Indexed/Direct RGB)
Graphical Primitive Elements (Class 4):
- POLYLINE, POLYGON, TEXT, RECTANGLE, CIRCLE, CIRCULAR ARC (partial), ELLIPSE (simplified)
Attribute Elements (Class 5):
- LINE WIDTH, LINE COLOUR (8-bit and 16-bit), FILL COLOUR (8-bit and 16-bit)
- EDGE WIDTH, EDGE COLOUR, EDGE VISIBILITY, INTERIOR STYLE
- Element 23 (HiJaak Fill Color Extension) ⭐
Drawing Records:
- META_MOVETO, META_LINETO - Line drawing
- META_POLYLINE, META_POLYGON - Multi-point shapes
- META_RECTANGLE, META_ROUNDRECT, META_ELLIPSE - Basic shapes
- META_TEXTOUT - Text rendering (basic)
Attribute Records:
- META_SETBKCOLOR - Background color
- META_SETWINDOWORG, META_SETWINDOWEXT - Window transformation
- META_SETVIEWPORTORG, META_SETVIEWPORTEXT - Viewport transformation
- META_SETMAPMODE - Coordinate mapping mode
Object Management:
- META_CREATEPENINDIRECT - Create pen objects
- META_CREATEBRUSHINDIRECT - Create brush objects
- META_SELECTOBJECT - Select GDI object
- META_DELETEOBJECT - Delete GDI object
This viewer includes special support for HiJaak 2 MIL-D-28003/BASIC-1 CGM files, which use vendor-specific extensions:
- Element 23 - Per-primitive fill color (not in ISO/IEC 8632 standard)
- Proper handling of "Hollow" interior style
- 16-bit RGB color values (converted to 8-bit internally)
- Direct RGB color mode (color_mode=1)
Files from HiJaak software (military/technical documentation) will now render correctly!
Implementation: Both vvi_viewer.py (lines 651-664) and cgm_to_svg.py (lines 149-156) handle Element 23 by treating it as a fill color attribute, which is non-standard but necessary for HiJaak files.
CGM: ✅ Standard ISO/IEC 8632 CGM files ✅ HiJaak 2 MIL-D-28003/BASIC-1 format ✅ Binary encoding ✅ Direct RGB and Indexed color modes ✅ 8-bit and 16-bit color precision
WMF: ✅ Standard Windows Metafile format ✅ Placeable metafiles (APM header) ✅ Windows 3.x era metafiles ✅ GDI-based graphics primitives
- This is a viewer for educational purposes
- Not all CGM elements are fully supported
- Complex CGM files may not render perfectly
- Text rendering uses default fonts
- Some advanced features (patterns, hatching, etc.) are not implemented
- Clear text CGM format not yet supported
CGM is an ISO standard (ISO/IEC 8632) for 2D vector graphics. This viewer supports binary-encoded CGM files including vendor extensions.
For detailed format information, see cgm_fileformat.md in this repository.
WMF is Microsoft's 16-bit graphics metafile format from the Windows 3.x era. It stores a sequence of GDI (Graphics Device Interface) function calls for vector graphics.
For detailed format information, see wmf_fileformat.md in this repository.
vvi_viewer.py (GUI Application)
├── tkinter (GUI framework - uses TCL/Tk)
├── PIL/Pillow (image rendering)
├── struct (binary parsing)
├── wmf_parser.py (WMF parsing and rendering)
└── cgm_to_svg.py (CGM SVG export)
└── cgm_svg_renderer.py (SVG generation)
GUI Viewer (vvi_viewer.py):
- File Loading: User selects CGM file via tkinter dialog
- Binary Parsing: Reads CGM command headers (element class, ID, parameters)
- Coordinate Transformation: Converts VDC (Virtual Device Coordinates) to screen pixels
- Raster Rendering: Uses PIL/Pillow ImageDraw to render primitives
- Display: Shows rendered image on tkinter Canvas
- Export: Can save as PNG (direct) or SVG (via
cgm_to_svg.py)
SVG Converter (cgm_to_svg.py):
- Binary Parsing: Reads CGM command headers (same logic as GUI)
- Vector Rendering: Calls
CGMSVGRenderermethods to build SVG elements - SVG Generation: Outputs XML-based SVG file
CGMRenderer (in vvi_viewer.py, lines 15-234)
- PIL-based raster renderer
- Maintains graphics state (colors, line widths, styles)
- Methods:
draw_polyline(),draw_polygon(),draw_rectangle(),draw_circle(),draw_text() - Returns: PIL Image object
CGMViewer (in vvi_viewer.py, lines 237-780)
- Tkinter GUI application
- CGM binary parser
- File navigation management
- Export functionality
CGMSVGRenderer (in cgm_svg_renderer.py)
- Pure Python SVG generator (no external dependencies)
- Same API as
CGMRendererbut outputs SVG elements - Returns: SVG XML string
Vintage-VectorImage-Viewer/
├── vvi_viewer.py # Main GUI application (multi-format viewer)
├── wmf_parser.py # WMF parser and renderer
├── cgm_to_svg.py # Command-line CGM to SVG converter
├── cgm_svg_renderer.py # SVG rendering engine
├── requirements.txt # Python dependencies
├── LICENSE # MIT License
├── README.md # This file
├── CLAUDE.md # Development guide and architecture notes
├── FEATURES.md # Feature list and implementation status
├── cgm_fileformat.md # Detailed CGM format specification
├── wmf_fileformat.md # Detailed WMF format specification
├── test_features.sh # Automated test script
└── Sample_Files/ # Sample vector graphics files
├── OWL1.CGM # Sample HiJaak CGM test file (1994)
├── BUTRFLY.WMF # Sample WMF file
└── sample.wmf # Sample WMF file
All black rendering?
- File may use HiJaak vendor extensions (Element 23)
- Check color selection mode: indexed (0) vs direct RGB (1)
- Verify that
vvi_viewer.py:651-664is handling Element 23 - Open the CGM file and check for non-standard elements
Colors wrong?
- Check color selection mode (indexed vs direct RGB)
- Mode set by Picture Descriptor element (class 2, id 2)
- Verify color precision (8-bit vs 16-bit)
- Parser converts 16-bit to 8-bit:
vvi_viewer.py:614-617
- Parser converts 16-bit to 8-bit:
- Color table may not be initialized (check element class 5, id 34)
Missing shapes or invisible fills?
- Interior style may be set to Empty (4) or Hollow (0)
- Check
set_interior_style()calls in parser
- Check
- Fill colors not being set properly
- Look for Fill Colour element (class 5, id 23)
- VDC extent may be incorrect
- Check VDC EXTENT element (class 2, id 6)
ModuleNotFoundError: No module named 'tkinter'
- tkinter not included with your Python installation
- See "Installing tkinter" section above
- On Linux:
sudo apt-get install python3-tk
ModuleNotFoundError: No module named 'PIL'
- Pillow not installed
- Run:
pip install -r requirements.txt - Or:
pip install pillow
GUI window doesn't appear
- Check if X11/display server is running (Linux)
- On WSL, install VcXsrv or use WSLg (Windows 11)
- Verify tkinter installation:
python -c "import tkinter; tkinter.Tk()"
struct.error or parsing errors
- File may be corrupted
- File may use clear text encoding (not supported yet)
- Check file starts with binary CGM header (not ASCII)
Unexpected end of file
- CGM file truncated
- Missing END METAFILE element
- Parser stops at position where header extends beyond file
The repository includes a test script:
bash test_features.shThis script tests the SVG conversion with the included OWL1.CGM sample file.
For developers working on this codebase:
CLAUDE.md- Architecture guide, design decisions, coding conventionsFEATURES.md- Feature implementation statuscgm_fileformat.md- Detailed CGM binary format specification with examples
To add support for a new CGM element:
- Identify element class and ID from CGM spec
- Add parser logic in
vvi_viewer.py:507-692(GUI renderer) - Add corresponding logic in
cgm_to_svg.py:75-168(SVG converter) - Implement rendering in
CGMRendererandCGMSVGRendererclasses - Test with sample files containing the element
- Parser: Binary CGM parsing is in
render_cgm_graphics()method - Renderer: Two implementations with same API
CGMRenderer(PIL-based, raster)CGMSVGRenderer(pure Python, vector)
- Coordinate transform:
transform_coords()method handles VDC to screen mapping
Standard Library (no install needed):
tkinter- GUI framework (TCL/Tk binding)struct- Binary data parsingos- File system operationssys- System operationsio- I/O operations
External (install via pip):
Pillow- Image rendering and manipulation
This project is licensed under the MIT License - see the LICENSE file for details.
- Based on ISO/IEC 8632 CGM specification
- Special thanks to the CGM format documentation community
- HiJaak extensions reverse-engineered from file analysis
- Sample file OWL1.CGM from 1994 HiJaak Pro software
- ISO/IEC 8632-1:1999 - Computer graphics — Metafile for the storage and transfer of picture description information
- MIL-D-28003/BASIC-1 - Military standard for CGM (with HiJaak extensions)
cgm_fileformat.md- Detailed format documentation in this repository
Made with ❤️ by Reinaldo Torres — reyco2000@gmail.com
Co-Coded with Anthropic's Claude Code
See more on Youtube @ChipShift | GitHub