vectory 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/docs.yml +59 -0
- data/.github/workflows/links.yml +99 -0
- data/.github/workflows/rake.yml +5 -1
- data/.github/workflows/release.yml +7 -3
- data/.gitignore +5 -0
- data/.rubocop.yml +11 -3
- data/.rubocop_todo.yml +252 -0
- data/Gemfile +4 -2
- data/README.adoc +23 -1
- data/Rakefile +13 -0
- data/docs/Gemfile +18 -0
- data/docs/_config.yml +179 -0
- data/docs/features/conversion.adoc +205 -0
- data/docs/features/external-dependencies.adoc +305 -0
- data/docs/features/format-detection.adoc +173 -0
- data/docs/features/index.adoc +205 -0
- data/docs/getting-started/core-concepts.adoc +214 -0
- data/docs/getting-started/index.adoc +37 -0
- data/docs/getting-started/installation.adoc +318 -0
- data/docs/getting-started/quick-start.adoc +160 -0
- data/docs/guides/error-handling.adoc +400 -0
- data/docs/guides/index.adoc +197 -0
- data/docs/index.adoc +146 -0
- data/docs/lychee.toml +25 -0
- data/docs/reference/api.adoc +355 -0
- data/docs/reference/index.adoc +189 -0
- data/docs/understanding/architecture.adoc +277 -0
- data/docs/understanding/index.adoc +148 -0
- data/docs/understanding/inkscape-wrapper.adoc +270 -0
- data/lib/vectory/capture.rb +165 -37
- data/lib/vectory/cli.rb +2 -0
- data/lib/vectory/configuration.rb +177 -0
- data/lib/vectory/conversion/ghostscript_strategy.rb +77 -0
- data/lib/vectory/conversion/inkscape_strategy.rb +124 -0
- data/lib/vectory/conversion/strategy.rb +58 -0
- data/lib/vectory/conversion.rb +104 -0
- data/lib/vectory/datauri.rb +1 -1
- data/lib/vectory/emf.rb +17 -5
- data/lib/vectory/eps.rb +45 -3
- data/lib/vectory/errors.rb +25 -0
- data/lib/vectory/file_magic.rb +2 -2
- data/lib/vectory/ghostscript_wrapper.rb +160 -0
- data/lib/vectory/image_resize.rb +2 -2
- data/lib/vectory/inkscape_wrapper.rb +205 -0
- data/lib/vectory/pdf.rb +76 -0
- data/lib/vectory/platform.rb +105 -0
- data/lib/vectory/ps.rb +47 -3
- data/lib/vectory/svg.rb +46 -3
- data/lib/vectory/svg_document.rb +40 -24
- data/lib/vectory/system_call.rb +36 -9
- data/lib/vectory/vector.rb +3 -23
- data/lib/vectory/version.rb +1 -1
- data/lib/vectory.rb +16 -11
- metadata +34 -3
- data/lib/vectory/inkscape_converter.rb +0 -141
data/docs/_config.yml
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Jekyll configuration for Vectory documentation
|
|
2
|
+
# Uses Just the Docs theme - https://just-the-docs.com/
|
|
3
|
+
|
|
4
|
+
# Site settings
|
|
5
|
+
title: Vectory
|
|
6
|
+
description: Vector image conversion library for Ruby (EPS, PS, EMF, SVG)
|
|
7
|
+
url: https://claricle.github.io
|
|
8
|
+
baseurl: /vectory
|
|
9
|
+
|
|
10
|
+
# Repository
|
|
11
|
+
repository: claricle/vectory
|
|
12
|
+
|
|
13
|
+
# Theme
|
|
14
|
+
theme: just-the-docs
|
|
15
|
+
remote_theme: just-the-docs/just-the-docs@v0.7.0
|
|
16
|
+
color_scheme: light
|
|
17
|
+
|
|
18
|
+
# AsciiDoc support
|
|
19
|
+
asciidoc: {}
|
|
20
|
+
asciidoctor:
|
|
21
|
+
attributes:
|
|
22
|
+
idprefix: ''
|
|
23
|
+
idseparator: '-'
|
|
24
|
+
source-highlighter: rouge
|
|
25
|
+
icons: font
|
|
26
|
+
experimental: true
|
|
27
|
+
sectanchors: true
|
|
28
|
+
linkattrs: true
|
|
29
|
+
sectnums: true
|
|
30
|
+
toc: left
|
|
31
|
+
toclevels: 3
|
|
32
|
+
|
|
33
|
+
# Search configuration
|
|
34
|
+
search_enabled: true
|
|
35
|
+
search:
|
|
36
|
+
heading_level: 3
|
|
37
|
+
previews: 3
|
|
38
|
+
preview_words_before: 5
|
|
39
|
+
preview_words_after: 10
|
|
40
|
+
tokenizer_separator: /[\s/]+/
|
|
41
|
+
rel_url: true
|
|
42
|
+
button: true
|
|
43
|
+
|
|
44
|
+
# Navigation
|
|
45
|
+
nav_sort: case_insensitive
|
|
46
|
+
nav_fold: true
|
|
47
|
+
|
|
48
|
+
# External links
|
|
49
|
+
aux_links:
|
|
50
|
+
"Source":
|
|
51
|
+
- "https://github.com/claricle/vectory"
|
|
52
|
+
"Report Issues":
|
|
53
|
+
- "https://github.com/claricle/vectory/issues"
|
|
54
|
+
"RubyGems":
|
|
55
|
+
- "https://rubygems.org/gems/vectory"
|
|
56
|
+
|
|
57
|
+
aux_links_new_tab: true
|
|
58
|
+
|
|
59
|
+
# Back to top
|
|
60
|
+
back_to_top: true
|
|
61
|
+
back_to_top_text: "Back to top"
|
|
62
|
+
|
|
63
|
+
# Heading anchors
|
|
64
|
+
heading_anchors: true
|
|
65
|
+
|
|
66
|
+
# Footer
|
|
67
|
+
footer_content: 'Copyright © 2025 Ribose. Distributed under the <a href="https://github.com/claricle/vectory/blob/main/LICENSE">MIT License</a>.'
|
|
68
|
+
|
|
69
|
+
# Footer last edit timestamp
|
|
70
|
+
last_edit_timestamp: true
|
|
71
|
+
last_edit_time_format: "%b %e %Y at %I:%M %p"
|
|
72
|
+
|
|
73
|
+
# Enable code copy button
|
|
74
|
+
enable_copy_code_button: true
|
|
75
|
+
|
|
76
|
+
# Callouts
|
|
77
|
+
callouts_level: quiet
|
|
78
|
+
callouts:
|
|
79
|
+
highlight:
|
|
80
|
+
color: yellow
|
|
81
|
+
important:
|
|
82
|
+
title: Important
|
|
83
|
+
color: blue
|
|
84
|
+
new:
|
|
85
|
+
title: New
|
|
86
|
+
color: green
|
|
87
|
+
note:
|
|
88
|
+
title: Note
|
|
89
|
+
color: purple
|
|
90
|
+
warning:
|
|
91
|
+
title: Warning
|
|
92
|
+
color: red
|
|
93
|
+
|
|
94
|
+
# Plugins
|
|
95
|
+
plugins:
|
|
96
|
+
- jekyll-asciidoc
|
|
97
|
+
- jekyll-seo-tag
|
|
98
|
+
- jekyll-sitemap
|
|
99
|
+
|
|
100
|
+
# Markdown settings (for any markdown files)
|
|
101
|
+
markdown: kramdown
|
|
102
|
+
kramdown:
|
|
103
|
+
input: GFM
|
|
104
|
+
hard_wrap: false
|
|
105
|
+
syntax_highlighter: rouge
|
|
106
|
+
|
|
107
|
+
# Collections for organizing content
|
|
108
|
+
collections:
|
|
109
|
+
# Core documentation pages (getting-started, interfaces, etc.)
|
|
110
|
+
pages:
|
|
111
|
+
permalink: "/:path/"
|
|
112
|
+
output: true
|
|
113
|
+
|
|
114
|
+
# Feature documentation
|
|
115
|
+
features:
|
|
116
|
+
permalink: "/:collection/:path/"
|
|
117
|
+
output: true
|
|
118
|
+
|
|
119
|
+
# Understanding/internal documentation
|
|
120
|
+
understanding:
|
|
121
|
+
permalink: "/:collection/:path/"
|
|
122
|
+
output: true
|
|
123
|
+
|
|
124
|
+
# Guides (task-oriented tutorials)
|
|
125
|
+
guides:
|
|
126
|
+
permalink: "/:collection/:path/"
|
|
127
|
+
output: true
|
|
128
|
+
|
|
129
|
+
# Reference documentation
|
|
130
|
+
reference:
|
|
131
|
+
permalink: "/:collection/:path/"
|
|
132
|
+
output: true
|
|
133
|
+
|
|
134
|
+
# # Just the Docs collection configuration
|
|
135
|
+
# just_the_docs:
|
|
136
|
+
# collections:
|
|
137
|
+
# pages:
|
|
138
|
+
# name: Pages
|
|
139
|
+
# nav_fold: false
|
|
140
|
+
# features:
|
|
141
|
+
# name: Features
|
|
142
|
+
# nav_fold: true
|
|
143
|
+
# understanding:
|
|
144
|
+
# name: Understanding
|
|
145
|
+
# nav_fold: true
|
|
146
|
+
# guides:
|
|
147
|
+
# name: Guides
|
|
148
|
+
# nav_fold: true
|
|
149
|
+
# reference:
|
|
150
|
+
# name: Reference
|
|
151
|
+
# nav_fold: true
|
|
152
|
+
|
|
153
|
+
# Defaults
|
|
154
|
+
defaults:
|
|
155
|
+
- scope:
|
|
156
|
+
path: ""
|
|
157
|
+
type: pages
|
|
158
|
+
values:
|
|
159
|
+
layout: default
|
|
160
|
+
|
|
161
|
+
# Include additional files
|
|
162
|
+
include:
|
|
163
|
+
- "*.adoc"
|
|
164
|
+
|
|
165
|
+
# Exclude from processing
|
|
166
|
+
exclude:
|
|
167
|
+
- Gemfile
|
|
168
|
+
- Gemfile.lock
|
|
169
|
+
- node_modules
|
|
170
|
+
- vendor
|
|
171
|
+
- .sass-cache
|
|
172
|
+
- .jekyll-cache
|
|
173
|
+
- .bundle
|
|
174
|
+
- README.md
|
|
175
|
+
- LICENSE
|
|
176
|
+
- .git
|
|
177
|
+
- .gitignore
|
|
178
|
+
|
|
179
|
+
permalink: pretty
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Conversion Features
|
|
4
|
+
parent: Features
|
|
5
|
+
nav_order: 1
|
|
6
|
+
---
|
|
7
|
+
= Conversion Features
|
|
8
|
+
|
|
9
|
+
How Vectory converts between vector image formats.
|
|
10
|
+
|
|
11
|
+
== Overview
|
|
12
|
+
|
|
13
|
+
Vectory supports pairwise conversion between EPS, PS, EMF, SVG, and PDF formats. Conversions are performed through external tools (Inkscape, Ghostscript, emf2svg) with a unified Ruby interface.
|
|
14
|
+
|
|
15
|
+
== Conversion Paths
|
|
16
|
+
|
|
17
|
+
=== Direct Conversions (via Inkscape)
|
|
18
|
+
|
|
19
|
+
Inkscape handles direct conversions between SVG and other formats:
|
|
20
|
+
|
|
21
|
+
* **SVG → EPS**: Export SVG to Encapsulated PostScript
|
|
22
|
+
* **SVG → PS**: Export SVG to PostScript
|
|
23
|
+
* **SVG → EMF**: Export SVG to Enhanced Metafile
|
|
24
|
+
* **SVG → PDF**: Export SVG to PDF
|
|
25
|
+
* **EPS → SVG**: Import EPS and export to SVG
|
|
26
|
+
* **PS → SVG**: Import PS and export to SVG
|
|
27
|
+
* **EMF → SVG**: Import EMF and export to SVG
|
|
28
|
+
* **PDF → SVG**: Import PDF and export to SVG
|
|
29
|
+
|
|
30
|
+
[source,ruby]
|
|
31
|
+
----
|
|
32
|
+
# Direct conversion examples
|
|
33
|
+
svg_to_eps = Vectory::Svg.from_path("diagram.svg").to_eps
|
|
34
|
+
eps_to_svg = Vectory::Eps.from_path("diagram.eps").to_svg
|
|
35
|
+
----
|
|
36
|
+
|
|
37
|
+
=== Two-Step Conversions (EPS/PS → SVG)
|
|
38
|
+
|
|
39
|
+
EPS and PS files are converted to SVG through a PDF intermediate:
|
|
40
|
+
|
|
41
|
+
1. **EPS/PS → PDF** (via Ghostscript): Preserves BoundingBox information
|
|
42
|
+
2. **PDF → SVG** (via Inkscape): Converts PDF to SVG
|
|
43
|
+
|
|
44
|
+
[source,ruby]
|
|
45
|
+
----
|
|
46
|
+
# Two-step conversion (automatic)
|
|
47
|
+
eps = Vectory::Eps.from_path("diagram.eps")
|
|
48
|
+
svg = eps.to_svg # Internally: EPS → PDF → SVG
|
|
49
|
+
----
|
|
50
|
+
|
|
51
|
+
This two-step process ensures accurate dimension preservation from EPS/PS files.
|
|
52
|
+
|
|
53
|
+
=== EMF Conversions (via emf2svg)
|
|
54
|
+
|
|
55
|
+
EMF files are converted using the emf2svg gem:
|
|
56
|
+
|
|
57
|
+
[source,ruby]
|
|
58
|
+
----
|
|
59
|
+
# EMF to SVG conversion
|
|
60
|
+
emf = Vectory::Emf.from_path("chart.emf")
|
|
61
|
+
svg = emf.to_svg # Uses emf2svg gem
|
|
62
|
+
----
|
|
63
|
+
|
|
64
|
+
== Conversion Matrix
|
|
65
|
+
|
|
66
|
+
[cols="2,1a,2a"]
|
|
67
|
+
|===
|
|
68
|
+
|Source|Target|Tool Used
|
|
69
|
+
|
|
70
|
+
|SVG|EPS|Inkscape
|
|
71
|
+
|SVG|PS|Inkscape
|
|
72
|
+
|SVG|EMF|Inkscape
|
|
73
|
+
|SVG|PDF|Inkscape
|
|
74
|
+
|
|
75
|
+
|EPS|SVG|Ghostscript + Inkscape (two-step)
|
|
76
|
+
|EPS|PDF|Ghostscript
|
|
77
|
+
|EPS|PS|Via PDF intermediate
|
|
78
|
+
|
|
79
|
+
|PS|SVG|Ghostscript + Inkscape (two-step)
|
|
80
|
+
|PS|PDF|Ghostscript
|
|
81
|
+
|PS|EPS|Via PDF intermediate
|
|
82
|
+
|
|
83
|
+
|EMF|SVG|emf2svg gem
|
|
84
|
+
|EMF|EPS|Via SVG intermediate
|
|
85
|
+
|EMF|PS|Via SVG intermediate
|
|
86
|
+
|
|
87
|
+
|PDF|SVG|Inkscape
|
|
88
|
+
|PDF|EPS|Via SVG intermediate
|
|
89
|
+
|PDF|PS|Via SVG intermediate
|
|
90
|
+
|===
|
|
91
|
+
|
|
92
|
+
== Quality Considerations
|
|
93
|
+
|
|
94
|
+
=== BoundingBox Preservation
|
|
95
|
+
|
|
96
|
+
Ghostscript preserves exact BoundingBox dimensions from EPS/PS files when converting to PDF:
|
|
97
|
+
|
|
98
|
+
[source,ruby]
|
|
99
|
+
----
|
|
100
|
+
eps = Vectory::Eps.from_path("diagram.eps")
|
|
101
|
+
pdf = eps.to_pdf # BoundingBox preserved exactly
|
|
102
|
+
----
|
|
103
|
+
|
|
104
|
+
=== Font Handling
|
|
105
|
+
|
|
106
|
+
* **Ghostscript**: Embeds fonts in PDF intermediate
|
|
107
|
+
* **Inkscape**: May convert fonts to paths for SVG output
|
|
108
|
+
|
|
109
|
+
=== Precision
|
|
110
|
+
|
|
111
|
+
Vector graphics maintain full precision through conversions. Rasterization does not occur.
|
|
112
|
+
|
|
113
|
+
== Performance
|
|
114
|
+
|
|
115
|
+
=== Conversion Speed
|
|
116
|
+
|
|
117
|
+
* **Direct conversions** (via Inkscape): ~1-3 seconds for typical files
|
|
118
|
+
* **Two-step conversions** (EPS/PS → SVG): ~2-5 seconds (Ghostscript + Inkscape)
|
|
119
|
+
* **EMF conversions** (via emf2svg): ~1-2 seconds
|
|
120
|
+
|
|
121
|
+
=== Caching
|
|
122
|
+
|
|
123
|
+
Vectory caches external tool information:
|
|
124
|
+
|
|
125
|
+
* **Inkscape version**: Detected once per session
|
|
126
|
+
* **Tool paths**: Discovered once and cached
|
|
127
|
+
|
|
128
|
+
[source,ruby]
|
|
129
|
+
----
|
|
130
|
+
# Version detection is cached
|
|
131
|
+
inkscape = Vectory::InkscapeWrapper.instance
|
|
132
|
+
puts inkscape.version # Cached result
|
|
133
|
+
----
|
|
134
|
+
|
|
135
|
+
== Common Conversion Tasks
|
|
136
|
+
|
|
137
|
+
=== Batch Conversions
|
|
138
|
+
|
|
139
|
+
Convert multiple files in a directory:
|
|
140
|
+
|
|
141
|
+
[source,ruby]
|
|
142
|
+
----
|
|
143
|
+
Dir["diagrams/*.eps"].each do |eps_file|
|
|
144
|
+
svg = Vectory::Eps.from_path(eps_file).to_svg
|
|
145
|
+
svg.write(eps_file.sub(".eps", ".svg"))
|
|
146
|
+
end
|
|
147
|
+
----
|
|
148
|
+
|
|
149
|
+
=== Content Conversion
|
|
150
|
+
|
|
151
|
+
Convert from content string without writing to disk:
|
|
152
|
+
|
|
153
|
+
[source,ruby]
|
|
154
|
+
----
|
|
155
|
+
eps_content = File.read("diagram.eps")
|
|
156
|
+
svg = Vectory::Eps.from_content(eps_content).to_svg
|
|
157
|
+
svg_content = svg.content
|
|
158
|
+
----
|
|
159
|
+
|
|
160
|
+
=== Dimension-Preserving Conversion
|
|
161
|
+
|
|
162
|
+
Query dimensions before conversion:
|
|
163
|
+
|
|
164
|
+
[source,ruby]
|
|
165
|
+
----
|
|
166
|
+
eps = Vectory::Eps.from_path("diagram.eps")
|
|
167
|
+
width, height = eps.dimensions
|
|
168
|
+
puts "Original size: #{width}x#{height}"
|
|
169
|
+
|
|
170
|
+
svg = eps.to_svg
|
|
171
|
+
svg_width, svg_height = svg.dimensions
|
|
172
|
+
puts "Converted size: #{svg_width}x#{svg_height}"
|
|
173
|
+
----
|
|
174
|
+
|
|
175
|
+
== Error Handling
|
|
176
|
+
|
|
177
|
+
=== Conversion Failures
|
|
178
|
+
|
|
179
|
+
[source,ruby]
|
|
180
|
+
----
|
|
181
|
+
begin
|
|
182
|
+
svg = Vectory::Eps.from_path("invalid.eps").to_svg
|
|
183
|
+
rescue Vectory::ConversionError => e
|
|
184
|
+
puts "Conversion failed: #{e.message}"
|
|
185
|
+
puts "Diagnostics: #{e.diagnostics}"
|
|
186
|
+
end
|
|
187
|
+
----
|
|
188
|
+
|
|
189
|
+
=== Tool Not Found
|
|
190
|
+
|
|
191
|
+
[source,ruby]
|
|
192
|
+
----
|
|
193
|
+
begin
|
|
194
|
+
svg = Vectory::Eps.from_path("diagram.eps").to_svg
|
|
195
|
+
rescue Vectory::InkscapeNotFoundError => e
|
|
196
|
+
puts "Inkscape not found: #{e.message}"
|
|
197
|
+
puts "Install Inkscape or set INKSCAPE_PATH"
|
|
198
|
+
end
|
|
199
|
+
----
|
|
200
|
+
|
|
201
|
+
== See Also
|
|
202
|
+
|
|
203
|
+
* link:../understanding/conversion-pipeline/[Conversion Pipeline] - Internal conversion architecture
|
|
204
|
+
* link:../guides/error-handling/[Error Handling Guide] - Common errors and solutions
|
|
205
|
+
* link:../reference/api/[API Reference] - Conversion method documentation
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: External Dependencies
|
|
4
|
+
parent: Features
|
|
5
|
+
nav_order: 3
|
|
6
|
+
---
|
|
7
|
+
= External Dependencies
|
|
8
|
+
|
|
9
|
+
Comprehensive guide to external tools and gems used by Vectory.
|
|
10
|
+
|
|
11
|
+
== Overview
|
|
12
|
+
|
|
13
|
+
Vectory relies on external tools for vector image conversion. This document explains each dependency, its purpose, and how Vectory integrates with it.
|
|
14
|
+
|
|
15
|
+
== Tool Dependencies
|
|
16
|
+
|
|
17
|
+
=== Inkscape
|
|
18
|
+
|
|
19
|
+
**Purpose**: Primary conversion engine
|
|
20
|
+
|
|
21
|
+
Inkscape handles most vector format conversions:
|
|
22
|
+
|
|
23
|
+
* SVG ↔ EPS/PS/EMF/PDF conversions
|
|
24
|
+
* Dimension queries
|
|
25
|
+
* High-quality vector output
|
|
26
|
+
|
|
27
|
+
**Version Requirements**:
|
|
28
|
+
|
|
29
|
+
* **Recommended**: 1.0 or later
|
|
30
|
+
* **Minimum**: 0.92
|
|
31
|
+
* **Windows**: 1.3.0 (1.3.1+ has EPS/PS issues)
|
|
32
|
+
|
|
33
|
+
**Integration**:
|
|
34
|
+
|
|
35
|
+
[source,ruby]
|
|
36
|
+
----
|
|
37
|
+
# Singleton pattern for efficiency
|
|
38
|
+
inkscape = Vectory::InkscapeWrapper.instance
|
|
39
|
+
|
|
40
|
+
# Version detection
|
|
41
|
+
puts inkscape.version # => "1.3.0"
|
|
42
|
+
|
|
43
|
+
# Executable path
|
|
44
|
+
puts inkscape.executable # => "/usr/bin/inkscape"
|
|
45
|
+
|
|
46
|
+
# Version-specific command generation
|
|
47
|
+
inkscape.modern? # => true for 1.x, false for 0.x
|
|
48
|
+
----
|
|
49
|
+
|
|
50
|
+
**Version Compatibility**:
|
|
51
|
+
|
|
52
|
+
Inkscape 0.x and 1.x use different command-line syntax. Vectory automatically detects the version and uses appropriate commands:
|
|
53
|
+
|
|
54
|
+
[source,ruby]
|
|
55
|
+
----
|
|
56
|
+
# Inkscape 0.x syntax
|
|
57
|
+
inkscape --file=input.svg --export-eps=output.eps
|
|
58
|
+
|
|
59
|
+
# Inkscape 1.x syntax
|
|
60
|
+
inkscape input.svg --export-type=eps --output-file=output.eps
|
|
61
|
+
----
|
|
62
|
+
|
|
63
|
+
Vectory handles this automatically.
|
|
64
|
+
|
|
65
|
+
**Known Issues**:
|
|
66
|
+
|
|
67
|
+
* **Inkscape 1.3.1+ on Windows**: EPS/PS conversion issues
|
|
68
|
+
* **macOS**: May timeout without `DISPLAY=""` environment variable
|
|
69
|
+
|
|
70
|
+
**Installation**: See link:../../getting-started/installation/[Installation Guide]
|
|
71
|
+
|
|
72
|
+
=== Ghostscript
|
|
73
|
+
|
|
74
|
+
**Purpose**: EPS/PS to PDF conversion
|
|
75
|
+
|
|
76
|
+
Ghostscript converts PostScript files to PDF while preserving:
|
|
77
|
+
|
|
78
|
+
* BoundingBox information
|
|
79
|
+
* Font embeddings
|
|
80
|
+
* Vector paths
|
|
81
|
+
|
|
82
|
+
**Version Requirements**:
|
|
83
|
+
|
|
84
|
+
* **Recommended**: 9.0 or later
|
|
85
|
+
* **Minimum**: 8.x (limited features)
|
|
86
|
+
|
|
87
|
+
**Integration**:
|
|
88
|
+
|
|
89
|
+
[source,ruby]
|
|
90
|
+
----
|
|
91
|
+
# Singleton pattern
|
|
92
|
+
gs = Vectory::GhostscriptWrapper.instance
|
|
93
|
+
|
|
94
|
+
# Executable path
|
|
95
|
+
puts gs.executable # => "/usr/bin/gs"
|
|
96
|
+
|
|
97
|
+
# EPS to PDF conversion
|
|
98
|
+
pdf = gs.eps_to_pdf("diagram.eps", "output.pdf")
|
|
99
|
+
----
|
|
100
|
+
|
|
101
|
+
**BoundingBox Preservation**:
|
|
102
|
+
|
|
103
|
+
[source,ruby]
|
|
104
|
+
----
|
|
105
|
+
# Ghostscript preserves exact BoundingBox
|
|
106
|
+
eps = Vectory::Eps.from_path("diagram.eps")
|
|
107
|
+
pdf = eps.to_pdf # BoundingBox preserved from EPS
|
|
108
|
+
----
|
|
109
|
+
|
|
110
|
+
**Installation**: See link:../../getting-started/installation/[Installation Guide]
|
|
111
|
+
|
|
112
|
+
== Gem Dependencies
|
|
113
|
+
|
|
114
|
+
=== emf2svg
|
|
115
|
+
|
|
116
|
+
**Purpose**: EMF format support
|
|
117
|
+
|
|
118
|
+
**Version**: ~> 1.0
|
|
119
|
+
|
|
120
|
+
emf2svg provides EMF to SVG conversion without external tool dependencies.
|
|
121
|
+
|
|
122
|
+
**Integration**:
|
|
123
|
+
|
|
124
|
+
[source,ruby]
|
|
125
|
+
----
|
|
126
|
+
# Automatic conversion
|
|
127
|
+
emf = Vectory::Emf.from_path("chart.emf")
|
|
128
|
+
svg = emf.to_svg # Uses emf2svg internally
|
|
129
|
+
----
|
|
130
|
+
|
|
131
|
+
**Features**:
|
|
132
|
+
|
|
133
|
+
* Cross-platform EMF support
|
|
134
|
+
* No external tool dependency
|
|
135
|
+
* Native Ruby implementation
|
|
136
|
+
|
|
137
|
+
=== moxml
|
|
138
|
+
|
|
139
|
+
**Purpose**: XML/HTML parsing (Metanorma integration)
|
|
140
|
+
|
|
141
|
+
**Version**: ~> 0.5
|
|
142
|
+
|
|
143
|
+
moxml parses XML/HTML for link:../../guides/metanorma-integration/[Metanorma SVG mapping].
|
|
144
|
+
|
|
145
|
+
**Integration**:
|
|
146
|
+
|
|
147
|
+
[source,ruby]
|
|
148
|
+
----
|
|
149
|
+
# Used internally by SvgMapping
|
|
150
|
+
require 'vectory/svg_mapping'
|
|
151
|
+
|
|
152
|
+
mapping = Vectory::SvgMapping.new(xml_doc, base_uri)
|
|
153
|
+
mapping.process # Uses moxml for parsing
|
|
154
|
+
----
|
|
155
|
+
|
|
156
|
+
**Features**:
|
|
157
|
+
|
|
158
|
+
* Link rewriting for embedded SVGs
|
|
159
|
+
* ID preservation and suffixing
|
|
160
|
+
* Namespace handling
|
|
161
|
+
|
|
162
|
+
== Tool Discovery
|
|
163
|
+
|
|
164
|
+
=== Automatic Discovery
|
|
165
|
+
|
|
166
|
+
Vectory automatically discovers tools in system PATH:
|
|
167
|
+
|
|
168
|
+
[source,ruby]
|
|
169
|
+
----
|
|
170
|
+
# Automatic discovery
|
|
171
|
+
inkscape = Vectory::InkscapeWrapper.instance
|
|
172
|
+
puts inkscape.executable # => "/usr/bin/inkscape" (or similar)
|
|
173
|
+
----
|
|
174
|
+
|
|
175
|
+
=== Custom Paths
|
|
176
|
+
|
|
177
|
+
Override with environment variables:
|
|
178
|
+
|
|
179
|
+
[source,bash]
|
|
180
|
+
----
|
|
181
|
+
export INKSCAPE_PATH="/custom/path/to/inkscape"
|
|
182
|
+
export GHOSTSCRIPT_PATH="/custom/path/to/gs"
|
|
183
|
+
----
|
|
184
|
+
|
|
185
|
+
Or in Ruby:
|
|
186
|
+
|
|
187
|
+
[source,ruby]
|
|
188
|
+
----
|
|
189
|
+
ENV["INKSCAPE_PATH"] = "/custom/path/to/inkscape"
|
|
190
|
+
inkscape = Vectory::InkscapeWrapper.instance
|
|
191
|
+
----
|
|
192
|
+
|
|
193
|
+
=== Verification
|
|
194
|
+
|
|
195
|
+
Check if tools are available:
|
|
196
|
+
|
|
197
|
+
[source,ruby]
|
|
198
|
+
----
|
|
199
|
+
# Check Inkscape
|
|
200
|
+
if Vectory::InkscapeWrapper.instance.available?
|
|
201
|
+
puts "Inkscape found"
|
|
202
|
+
else
|
|
203
|
+
puts "Inkscape not found"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Check Ghostscript
|
|
207
|
+
if Vectory::GhostscriptWrapper.instance.available?
|
|
208
|
+
puts "Ghostscript found"
|
|
209
|
+
else
|
|
210
|
+
puts "Ghostscript not found"
|
|
211
|
+
end
|
|
212
|
+
----
|
|
213
|
+
|
|
214
|
+
== Error Handling
|
|
215
|
+
|
|
216
|
+
=== Tool Not Found
|
|
217
|
+
|
|
218
|
+
[source,ruby]
|
|
219
|
+
----
|
|
220
|
+
begin
|
|
221
|
+
svg = Vectory::Eps.from_path("diagram.eps").to_svg
|
|
222
|
+
rescue Vectory::InkscapeNotFoundError => e
|
|
223
|
+
puts "Inkscape not found: #{e.message}"
|
|
224
|
+
puts "Install Inkscape or set INKSCAPE_PATH"
|
|
225
|
+
end
|
|
226
|
+
----
|
|
227
|
+
|
|
228
|
+
=== Version Incompatibility
|
|
229
|
+
|
|
230
|
+
[source,ruby]
|
|
231
|
+
----
|
|
232
|
+
# Check version compatibility
|
|
233
|
+
inkscape = Vectory::InkscapeWrapper.instance
|
|
234
|
+
if inkscape.version < "0.92"
|
|
235
|
+
puts "Warning: Inkscape version is too old"
|
|
236
|
+
end
|
|
237
|
+
----
|
|
238
|
+
|
|
239
|
+
=== Tool Execution Failures
|
|
240
|
+
|
|
241
|
+
[source,ruby]
|
|
242
|
+
----
|
|
243
|
+
begin
|
|
244
|
+
svg = Vectory::Eps.from_path("diagram.eps").to_svg
|
|
245
|
+
rescue Vectory::SystemCallError => e
|
|
246
|
+
puts "Tool execution failed: #{e.message}"
|
|
247
|
+
puts "Command: #{e.command}"
|
|
248
|
+
puts "Exit code: #{e.exit_code}"
|
|
249
|
+
end
|
|
250
|
+
----
|
|
251
|
+
|
|
252
|
+
== Platform-Specific Notes
|
|
253
|
+
|
|
254
|
+
=== macOS
|
|
255
|
+
|
|
256
|
+
* **Inkscape**: May timeout without `DISPLAY=""`
|
|
257
|
+
* **Fix**: Vectory automatically sets `DISPLAY=""` on macOS
|
|
258
|
+
|
|
259
|
+
=== Windows
|
|
260
|
+
|
|
261
|
+
* **Inkscape 1.3.1+**: EPS/PS conversion issues
|
|
262
|
+
* **Fix**: Use Inkscape 1.3.0
|
|
263
|
+
* **Process management**: Uses `taskkill` instead of `Process.kill`
|
|
264
|
+
|
|
265
|
+
=== Linux
|
|
266
|
+
|
|
267
|
+
* Standard Unix behavior
|
|
268
|
+
* Ensure proper file permissions
|
|
269
|
+
|
|
270
|
+
== CI/CD Integration
|
|
271
|
+
|
|
272
|
+
Example GitHub Actions setup:
|
|
273
|
+
|
|
274
|
+
[source,yaml]
|
|
275
|
+
----
|
|
276
|
+
- name: Install dependencies
|
|
277
|
+
run: |
|
|
278
|
+
sudo apt-get update
|
|
279
|
+
sudo apt-get install -y inkscape ghostscript
|
|
280
|
+
env:
|
|
281
|
+
DISPLAY: ""
|
|
282
|
+
|
|
283
|
+
- name: Run tests
|
|
284
|
+
run: bundle exec rspec
|
|
285
|
+
----
|
|
286
|
+
|
|
287
|
+
## Troubleshooting
|
|
288
|
+
|
|
289
|
+
**Inkscape timeout on macOS**::
|
|
290
|
+
Set `DISPLAY=""` environment variable (automatic in Vectory)
|
|
291
|
+
|
|
292
|
+
**Inkscape 1.3.1+ EPS issues on Windows**::
|
|
293
|
+
Downgrade to Inkscape 1.3.0
|
|
294
|
+
|
|
295
|
+
**Ghostscript not found**::
|
|
296
|
+
Install Ghostscript or set `GHOSTSCRIPT_PATH`
|
|
297
|
+
|
|
298
|
+
**emf2svg conversion fails**::
|
|
299
|
+
Ensure emf2svg gem is installed: `gem install emf2svg`
|
|
300
|
+
|
|
301
|
+
== See Also
|
|
302
|
+
|
|
303
|
+
* link:../../getting-started/installation/[Installation Guide] - Detailed setup instructions
|
|
304
|
+
* link:../understanding/inkscape-wrapper/[Inkscape Wrapper] - Technical details
|
|
305
|
+
* link:../understanding/ghostscript-wrapper/[Ghostscript Wrapper] - Technical details
|