Postsvg
Purpose
Postsvg is a pure Ruby library for converting PostScript (PS) and Encapsulated PostScript (EPS) files to Scalable Vector Graphics (SVG) format.
Unlike traditional approaches that rely on external tools like Ghostscript or Inkscape, Postsvg provides a native Ruby implementation using Parslet for parsing PostScript commands and generating clean, standards-compliant SVG output.
This library is particularly useful for applications that need to:
-
Convert legacy PostScript graphics to modern SVG format
-
Process vector graphics without external dependencies
-
Generate SVG from PostScript programmatically
-
Work with EPS files in pure Ruby environments == Documentation
π Complete Documentation - Comprehensive guides, API reference, and tutorials
Features
-
Basic PostScript to SVG conversion - Ruby API for converting PS/EPS content to SVG
-
Command-line interface - Thor-based CLI for file and batch conversions
-
PostScript language support - Comprehensive documentation and implementation
-
Pure Ruby architecture - No external dependencies, Parslet-based parser
-
SVG optimization - Automatic deduplication of clipPath elements for efficient output
-
Comprehensive test coverage - 90+ core tests with 100% pass rate on critical paths
Architecture
General
Postsvg uses a three-stage architecture for converting PostScript to SVG. This design follows separation of concerns principles, with each component handling a specific responsibility in the conversion process.
βββββββββββββββ βββββββββββββ ββββββββββββββββ
β PostScript βββ> β Parser βββ> β Converter β
β Input β β (Parslet) β β (Interpreter)β
βββββββββββββββ βββββββββββββ βββββββββ¬βββββββ
β
βΌ
βββββββββββββββββββ
β SVG Generator β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β SVG Output β
βββββββββββββββββββParser stage
The parser uses Parslet to tokenize and parse PostScript commands into an abstract syntax tree (AST). The parser handles PostScript syntax including numbers, operators, names, strings, arrays, and procedures.
-
Postsvg::Parser::PostscriptParser- Parslet grammar for PostScript syntax -
Postsvg::Parser::Transform- Transforms AST into Ruby data structures
Converter stage
The converter interprets PostScript commands using a stack-based execution model. It maintains an operand stack, dictionary, and graphics state while executing PostScript operators.
-
Postsvg::Converter- Main orchestrator that executes PostScript commands -
Postsvg::GraphicsState- Manages current path, colors, transformations, and graphics state stack
Generator stage
The generator creates SVG output from the interpreted graphics operations, handling coordinate system transformations and generating standards-compliant SVG markup.
-
Postsvg::SvgGenerator- Builds SVG document with proper structure and viewBox
Installation
Add this line to your applicationβs Gemfile:
gem "postsvg"And then execute:
bundle installOr install it yourself as:
gem install postsvgBasic PostScript to SVG conversion
General
The Postsvg library provides a simple Ruby API for converting PostScript content to SVG format. The conversion can be performed on in-memory content or directly on files.
The library automatically handles BoundingBox extraction, coordinate system transformations, and SVG generation while preserving the visual appearance of the original PostScript graphics.
Converting PostScript content
Syntax:
svg_output = Postsvg.convert(ps_content) (1)-
Convert PostScript string to SVG string
Where,
ps_content-
PostScript or EPS content as a string. Should include proper PostScript header and BoundingBox comment for best results.
- Returns
-
SVG markup as a string
require "postsvg"
ps_content = <<~PS
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 100 100
newpath
10 10 moveto
90 10 lineto
90 90 lineto
10 90 lineto
closepath
0.5 0.5 0.5 setrgbcolor
fill
PS
svg = Postsvg.convert(ps_content)
File.write("output.svg", svg)This converts a PostScript square with gray fill to SVG format and saves it to a file.
Converting PostScript files
Syntax:
Postsvg.convert_file(input_path, output_path) (1)
svg_content = Postsvg.convert_file(input_path) (2)-
Convert file and save to output path
-
Convert file and return SVG content without saving
Where,
input_path-
Path to input PostScript (.ps) or EPS (.eps) file
output_path-
(Optional) Path where SVG file should be saved. If omitted, SVG content is returned without saving.
- Returns
-
When
output_pathis omitted, returns SVG markup as a string. Whenoutput_pathis provided, returns the output path.
require "postsvg"
# Convert and save in one step
Postsvg.convert_file("input.eps", "output.svg")
# Or get SVG content without saving
svg_content = Postsvg.convert_file("input.ps")
puts svg_contentThe first example converts an EPS file and saves the result as SVG. The second example reads a PostScript file and returns the SVG content for further processing.
Command-line interface
General
Postsvg provides a Thor-based command-line interface for converting PostScript and EPS files to SVG format. The CLI supports single file conversion, batch processing, and version information.
The CLI is available through the postsvg executable installed with the
gem.
Converting single files
Syntax:
postsvg convert INPUT_FILE [OUTPUT_FILE] (1)-
Convert INPUT_FILE to SVG, optionally saving to OUTPUT_FILE
Where,
INPUT_FILE-
Path to input PostScript (.ps) or EPS (.eps) file
OUTPUT_FILE-
(Optional) Path where SVG file should be saved. If omitted, SVG is written to stdout.
# Convert to stdout
postsvg convert input.ps
# Convert and save to file
postsvg convert input.eps output.svg
# Redirect stdout to file
postsvg convert input.ps > output.svgThe first command prints SVG to stdout. The second saves directly to output.svg. The third uses shell redirection to save the output.
Batch conversion
Syntax:
postsvg batch INPUT_DIR [OUTPUT_DIR] (1)-
Convert all PS/EPS files in INPUT_DIR, optionally saving to OUTPUT_DIR
Where,
INPUT_DIR-
Directory containing PostScript (.ps) and/or EPS (.eps) files to convert
OUTPUT_DIR-
(Optional) Directory where SVG files should be saved. If omitted, SVG files are saved in the same directory as input files with .svg extension.
# Convert all PS/EPS files in a directory
postsvg batch ps_files/
# Convert to a different directory
postsvg batch ps_files/ svg_files/The first example converts all PS and EPS files in the ps_files/
directory, saving the SVG files in the same directory. The second
example saves the converted files to the svg_files/ directory.
Displaying version information
Syntax:
postsvg version (1)-
Display the Postsvg version number
postsvg versionOutput:
postsvg version 0.1.0
File validation
General
Postsvg includes a comprehensive validation tool for checking PostScript and EPS files. The validator performs syntax checking, semantic validation, and optional full conversion testing to ensure files are well-formed and can be successfully converted.
The validator is particularly useful for:
-
Verifying PostScript/EPS file integrity before conversion
-
Identifying syntax errors and structural issues
-
Validating compliance with PostScript standards
-
Integrating quality checks into CI/CD pipelines
Basic validation
Syntax:
postsvg check FILE... (1)-
Validate one or more PostScript or EPS files
Where,
FILE-
Path to PostScript (.ps) or EPS (.eps) file(s) to validate. Multiple files can be specified.
- Returns
-
Exit code 0 if all files are valid, 1 if any file has errors.
# Validate a single file
postsvg check document.ps
# Validate multiple files
postsvg check file1.ps file2.eps file3.ps
# Validate all PS files in directory
postsvg check *.psThe validator performs semantic-level validation by default, checking syntax, stack balance, and graphics state management.
Validation levels
Syntax:
postsvg check --level=LEVEL FILE... (1)-
Validate with specified level: syntax, semantic, or full
Where,
LEVEL-
One of:
-
syntax- Fast syntax-only validation (header, delimiters, tokenization) -
semantic- Default level (syntax + stack/state checking) -
full- Strictest validation (semantic + complete conversion test)
-
# Fast syntax-only check
postsvg check --level=syntax document.ps
# Default semantic validation
postsvg check --level=semantic document.ps
# Full validation with conversion test
postsvg check --level=full document.psSyntax validation is fastest but only checks basic file structure. Semantic validation adds stack and state checking. Full validation attempts complete conversion and is most thorough.
Output formats
Syntax:
postsvg check --format=FORMAT FILE... (1)-
Output validation results in specified format
Where,
FORMAT-
One of:
-
text- Human-readable colored console output (default) -
yaml- YAML structured format -
json- JSON structured format
-
# Default text output with colors
postsvg check document.ps
# YAML output
postsvg check --format=yaml document.ps
# JSON output for programmatic parsing
postsvg check --format=json document.ps
# JSON output without colors (for CI)
postsvg check --format=json --no-color document.psText format provides human-readable output with color-coded status indicators. YAML and JSON formats are useful for programmatic processing or integration with other tools.
Validation options
The validator supports additional options for controlling behavior and output:
--verbose-
Show warnings and info messages in addition to errors
--quiet-
Suppress output for valid files (only show errors)
--no-color-
Disable colored output
--fail-fast-
Stop validation at first error
--eps-version=VERSION-
Validate EPS version (e.g.,
3.0)
# Verbose output with all details
postsvg check --verbose document.eps
# Quiet mode - only show errors
postsvg check --quiet *.ps
# Stop at first error
postsvg check --fail-fast file1.ps file2.ps file3.ps
# Validate specific EPS version
postsvg check --eps-version=3.0 diagram.epsSVG optimization
General
Postsvg automatically optimizes SVG output to produce smaller, more efficient files while maintaining visual fidelity to the original PostScript graphics.
ClipPath deduplication
PostScript files often contain repeated clipping operations with identical paths. Postsvg automatically detects and deduplicates these clipPath definitions, significantly reducing SVG file size for documents with repeated clipping operations.
<defs>
<clipPath id="clipPath2">
<path d="M 0 0 L 100 100"/>
</clipPath>
<clipPath id="clipPath3">
<path d="M 0 0 L 100 100"/>
</clipPath>
<clipPath id="clipPath4">
<path d="M 0 0 L 100 100"/>
</clipPath>
</defs>Postsvg generates a single definition and reuses it:
<defs>
<clipPath id="clipPath2">
<path d="M 0 0 L 100 100"/>
</clipPath>
</defs>
<path clip-path="url(#clipPath2)" .../>
<path clip-path="url(#clipPath2)" .../>
<path clip-path="url(#clipPath2)" .../>This optimization is automatic and requires no configuration.
Test coverage
General
Postsvg maintains comprehensive test coverage to ensure reliability and correctness of PostScript to SVG conversion.
Core test suite
The core test suite consists of 90+ tests covering execution context and integration testing:
-
Execution context tests (84 tests) - Unit tests for stack operations, graphics state management, dictionary operations, path operations, helper methods, SVG generation, and clipPath deduplication
-
Integration tests (6 tests) - End-to-end tests using real PostScript files from ps2svg and vectory test suites
All core tests maintain 100% pass rate, ensuring critical functionality remains stable.
Running tests
Run the full test suite:
bundle exec rspecRun only core tests:
bundle exec rspec spec/postsvg/execution_context_spec.rb spec/postsvg/integration_spec.rbRun with documentation format:
bundle exec rspec --format documentationPostScript language support
General
Postsvg provides comprehensive PostScript language support with detailed documentation covering fundamentals, operators, and conversion strategies.
The implementation supports common PostScript operations including path construction, painting, color management, graphics state, and coordinate transformations.
PostScript documentation
Complete PostScript language documentation is available at docs/POSTSCRIPT.adoc, organized into the following topics:
-
Fundamentals - PostScript language basics, syntax, and data types
-
Graphics model - Coordinate systems, paths, and painting model
-
Operators reference - Detailed documentation for all supported operators:
-
Path construction - moveto, lineto, curveto, closepath, newpath
-
Painting - stroke, fill
-
Graphics state - gsave, grestore, setlinewidth
-
-
translate, scale, rotate
-
-
Stack manipulation - dup, pop, exch, roll
-
Arithmetic - add, sub, mul, div
-
Control flow - if, ifelse, for, repeat
-
Dictionary - def, dict, begin, end
-
-
SVG mapping guide - How PostScript operations map to SVG
-
Implementation notes - Postsvg-specific details and design decisions
Supported PostScript operations
Path construction
-
moveto- Begin new subpath at coordinates -
lineto- Append straight line segment -
rlineto- Append relative line segment -
curveto- Append cubic BΓ©zier curve -
closepath- Close current subpath -
newpath- Initialize new path
Painting
-
stroke- Stroke current path with current color and line width -
fill- Fill current path with current color
Color
-
setrgbcolor- Set RGB color (0-1 range for each component) -
setgray- Set grayscale color (0-1 range)
Graphics state
-
gsave- Save current graphics state to stack -
grestore- Restore graphics state from stack -
setlinewidth- Set line width for stroke operations
Transformations
-
translate- Translate coordinate system -
scale- Scale coordinate system -
rotate- Rotate coordinate system (angle in degrees)
Limitations
Current version has the following limitations:
-
Text rendering: Text operations (show, findfont, setfont, etc.) are not yet supported. Convert text to outlines before processing.
-
Complex clipping: Clipping paths (clip, eoclip) are not fully implemented
-
Gradients and patterns: Pattern fills and gradient operations are not yet supported
-
CMYK colors: Only RGB and grayscale colors are supported. CMYK color operations will need conversion.
-
Image embedding: Raster images within PostScript (image, imagemask) are not supported
-
Advanced operators: Some PostScript Level 2 and 3 operators are not yet implemented
For files with these features, consider preprocessing with external tools or contributing implementations of these features.
Acknowledgments
This project uses test fixtures from ps2svg by Emmett Lalish, licensed under the MIT License. These test files help ensure the correctness of our SVG generation against a reference implementation. We are grateful for this valuable resource that helps validate PostScript to SVG conversion.
Development
Running tests
bundle exec rspecCode style
bundle exec rubocopRunning all checks
bundle exec rakeContributing
Bug reports and pull requests are welcome on GitHub at https://github.com/metanorma/postsvg.
Copyright
Copyright Ribose.
License
The gem is available as open source under the terms of the BSD 2-Clause License.