postsvg 0.1.0 → 0.3.0
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/CHANGELOG.md +105 -0
- data/CLAUDE.md +173 -0
- data/Gemfile +2 -3
- data/README.adoc +456 -179
- data/Rakefile +100 -0
- data/TODO.roadmap/00-architecture.md +139 -0
- data/TODO.roadmap/01-autoload-migration.md +39 -0
- data/TODO.roadmap/02-isolate-dormant-code.md +51 -0
- data/TODO.roadmap/03-domain-model.md +66 -0
- data/TODO.roadmap/04-lexer.md +40 -0
- data/TODO.roadmap/05-parser.md +43 -0
- data/TODO.roadmap/06-graphics-state.md +45 -0
- data/TODO.roadmap/07-matrix-and-color.md +37 -0
- data/TODO.roadmap/08-svg-builder.md +51 -0
- data/TODO.roadmap/09-renderer.md +52 -0
- data/TODO.roadmap/10-visitor.md +58 -0
- data/TODO.roadmap/11-operator-coverage.md +103 -0
- data/TODO.roadmap/12-svg-domain.md +62 -0
- data/TODO.roadmap/13-translation-handlers.md +69 -0
- data/TODO.roadmap/14-ps-serializer.md +49 -0
- data/TODO.roadmap/15-cli-and-public-api.md +47 -0
- data/TODO.roadmap/16-specs.md +84 -0
- data/TODO.roadmap/17-docs-sync.md +47 -0
- data/TODO.roadmap/18-performance-and-determinism.md +47 -0
- data/TODO.roadmap/19-error-model.md +45 -0
- data/TODO.roadmap/20-font-and-text.md +46 -0
- data/TODO.roadmap/21-images.md +45 -0
- data/TODO.roadmap/22-forms-and-resources.md +25 -0
- data/TODO.roadmap/23-level2-level3.md +52 -0
- data/TODO.roadmap/24-ci-and-release.md +42 -0
- data/TODO.roadmap/README.md +77 -0
- data/docs/.gitignore +29 -0
- data/docs/CHANGELOG.md +114 -0
- data/docs/COMPLETE_DOCUMENTATION_STATUS.md +376 -0
- data/docs/DEPLOYMENT.md +456 -0
- data/docs/DEPLOYMENT_INSTRUCTIONS.md +229 -0
- data/docs/DOCUMENTATION_PLAN.md +425 -0
- data/docs/FINAL_SUMMARY.md +657 -0
- data/docs/Gemfile +15 -0
- data/docs/README.md +327 -0
- data/docs/_config.yml +99 -0
- data/docs/advanced-topics.adoc +370 -0
- data/docs/api-reference/colors.adoc +705 -0
- data/docs/api-reference/converter.adoc +699 -0
- data/docs/api-reference/execution-context.adoc +1210 -0
- data/docs/api-reference/graphics-state.adoc +1070 -0
- data/docs/api-reference/interpreter.adoc +810 -0
- data/docs/api-reference/matrix.adoc +1179 -0
- data/docs/api-reference/path-builder.adoc +1284 -0
- data/docs/api-reference/postsvg-module.adoc +388 -0
- data/docs/api-reference/svg-generator.adoc +891 -0
- data/docs/api-reference/tokenizer.adoc +925 -0
- data/docs/api-reference.adoc +221 -0
- data/docs/architecture/command-registry.adoc +1191 -0
- data/docs/architecture/conversion-pipeline.adoc +746 -0
- data/docs/architecture/design-decisions.adoc +999 -0
- data/docs/architecture/generator-stage.adoc +1115 -0
- data/docs/architecture/graphics-state-model.adoc +1089 -0
- data/docs/architecture/interpreter-stage.adoc +1125 -0
- data/docs/architecture/parser-stage.adoc +1051 -0
- data/docs/architecture.adoc +354 -0
- data/docs/cli-reference/batch-command.adoc +616 -0
- data/docs/cli-reference/check-command.adoc +677 -0
- data/docs/cli-reference/cli-options.adoc +802 -0
- data/docs/cli-reference/convert-command.adoc +462 -0
- data/docs/cli-reference/version-command.adoc +296 -0
- data/docs/cli-reference.adoc +317 -0
- data/docs/concepts/conversion-pipeline.adoc +903 -0
- data/docs/concepts/coordinate-systems.adoc +836 -0
- data/docs/concepts/graphics-state.adoc +861 -0
- data/docs/concepts/path-operations.adoc +1076 -0
- data/docs/concepts/postscript-language.adoc +859 -0
- data/docs/concepts/svg-generation.adoc +937 -0
- data/docs/concepts.adoc +198 -0
- data/docs/contributing.adoc +443 -0
- data/docs/development.adoc +420 -0
- data/docs/faq.adoc +493 -0
- data/docs/getting-started/basic-usage.adoc +538 -0
- data/docs/getting-started/common-workflows.adoc +577 -0
- data/docs/getting-started/first-conversion.adoc +492 -0
- data/docs/getting-started/installation.adoc +534 -0
- data/docs/getting-started.adoc +94 -0
- data/docs/index.adoc +248 -0
- data/docs/optimization.adoc +196 -0
- data/docs/ps2svg_compatibility.adoc +149 -0
- data/docs/quick-reference.adoc +453 -0
- data/docs/sitemap.adoc +337 -0
- data/docs/troubleshooting.adoc +486 -0
- data/docs/validation.adoc +772 -0
- data/exe/postsvg +1 -0
- data/lib/postsvg/cli.rb +104 -57
- data/lib/postsvg/color.rb +132 -0
- data/lib/postsvg/errors.rb +68 -3
- data/lib/postsvg/format_number.rb +22 -0
- data/lib/postsvg/graphics_context.rb +80 -0
- data/lib/postsvg/graphics_stack.rb +43 -0
- data/lib/postsvg/model/literals/array.rb +41 -0
- data/lib/postsvg/model/literals/dictionary.rb +34 -0
- data/lib/postsvg/model/literals/hex.rb +37 -0
- data/lib/postsvg/model/literals/name.rb +40 -0
- data/lib/postsvg/model/literals/number.rb +36 -0
- data/lib/postsvg/model/literals/procedure.rb +41 -0
- data/lib/postsvg/model/literals/string.rb +30 -0
- data/lib/postsvg/model/literals.rb +19 -0
- data/lib/postsvg/model/operator.rb +58 -0
- data/lib/postsvg/model/operators/arithmetic.rb +264 -0
- data/lib/postsvg/model/operators/boolean.rb +182 -0
- data/lib/postsvg/model/operators/color.rb +74 -0
- data/lib/postsvg/model/operators/container.rb +186 -0
- data/lib/postsvg/model/operators/control_flow.rb +119 -0
- data/lib/postsvg/model/operators/device.rb +21 -0
- data/lib/postsvg/model/operators/dictionary.rb +118 -0
- data/lib/postsvg/model/operators/font.rb +121 -0
- data/lib/postsvg/model/operators/graphics_state.rb +84 -0
- data/lib/postsvg/model/operators/painting.rb +29 -0
- data/lib/postsvg/model/operators/path.rb +169 -0
- data/lib/postsvg/model/operators/stack.rb +72 -0
- data/lib/postsvg/model/operators/transformations.rb +103 -0
- data/lib/postsvg/model/operators.rb +89 -0
- data/lib/postsvg/model/program.rb +68 -0
- data/lib/postsvg/model/token.rb +43 -0
- data/lib/postsvg/model.rb +17 -0
- data/lib/postsvg/options.rb +29 -0
- data/lib/postsvg/renderer.rb +85 -0
- data/lib/postsvg/serializer.rb +325 -0
- data/lib/postsvg/source/ast_builder.rb +308 -0
- data/lib/postsvg/source/lexer.rb +322 -0
- data/lib/postsvg/source/operand_stack.rb +55 -0
- data/lib/postsvg/source.rb +21 -0
- data/lib/postsvg/svg/attribute_parser.rb +45 -0
- data/lib/postsvg/svg/clip_path_registry.rb +44 -0
- data/lib/postsvg/svg/document.rb +22 -0
- data/lib/postsvg/svg/element.rb +84 -0
- data/lib/postsvg/svg/elements/circle.rb +36 -0
- data/lib/postsvg/svg/elements/clip_path.rb +26 -0
- data/lib/postsvg/svg/elements/defs.rb +24 -0
- data/lib/postsvg/svg/elements/ellipse.rb +38 -0
- data/lib/postsvg/svg/elements/group.rb +37 -0
- data/lib/postsvg/svg/elements/image.rb +35 -0
- data/lib/postsvg/svg/elements/line.rb +36 -0
- data/lib/postsvg/svg/elements/path.rb +32 -0
- data/lib/postsvg/svg/elements/polygon.rb +12 -0
- data/lib/postsvg/svg/elements/polyline.rb +32 -0
- data/lib/postsvg/svg/elements/rect.rb +44 -0
- data/lib/postsvg/svg/elements/svg.rb +39 -0
- data/lib/postsvg/svg/elements/text.rb +42 -0
- data/lib/postsvg/svg/elements.rb +31 -0
- data/lib/postsvg/svg/paint.rb +34 -0
- data/lib/postsvg/svg/parser.rb +39 -0
- data/lib/postsvg/svg/path_data/command.rb +27 -0
- data/lib/postsvg/svg/path_data/parser.rb +82 -0
- data/lib/postsvg/svg/path_data.rb +17 -0
- data/lib/postsvg/svg/stroke.rb +31 -0
- data/lib/postsvg/svg/transform_list.rb +59 -0
- data/lib/postsvg/svg.rb +22 -0
- data/lib/postsvg/svg_builder.rb +249 -0
- data/lib/postsvg/translation/arc_converter.rb +86 -0
- data/lib/postsvg/translation/bounding_box.rb +59 -0
- data/lib/postsvg/translation/context.rb +34 -0
- data/lib/postsvg/translation/handler_registry.rb +38 -0
- data/lib/postsvg/translation/handlers/circle_handler.rb +28 -0
- data/lib/postsvg/translation/handlers/clip_path_handler.rb +13 -0
- data/lib/postsvg/translation/handlers/defs_handler.rb +15 -0
- data/lib/postsvg/translation/handlers/ellipse_handler.rb +31 -0
- data/lib/postsvg/translation/handlers/group_handler.rb +21 -0
- data/lib/postsvg/translation/handlers/image_handler.rb +20 -0
- data/lib/postsvg/translation/handlers/line_handler.rb +23 -0
- data/lib/postsvg/translation/handlers/open_handler.rb +18 -0
- data/lib/postsvg/translation/handlers/path_handler.rb +356 -0
- data/lib/postsvg/translation/handlers/polygon_handler.rb +33 -0
- data/lib/postsvg/translation/handlers/polyline_handler.rb +31 -0
- data/lib/postsvg/translation/handlers/rect_handler.rb +27 -0
- data/lib/postsvg/translation/handlers/shared.rb +110 -0
- data/lib/postsvg/translation/handlers/svg_handler.rb +25 -0
- data/lib/postsvg/translation/handlers/text_handler.rb +56 -0
- data/lib/postsvg/translation/handlers.rb +25 -0
- data/lib/postsvg/translation/ps_renderer.rb +105 -0
- data/lib/postsvg/translation/record_emitter.rb +35 -0
- data/lib/postsvg/translation.rb +17 -0
- data/lib/postsvg/version.rb +1 -1
- data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +125 -0
- data/lib/postsvg/visitors/ps_visitor/boolean.rb +105 -0
- data/lib/postsvg/visitors/ps_visitor/color.rb +53 -0
- data/lib/postsvg/visitors/ps_visitor/common.rb +66 -0
- data/lib/postsvg/visitors/ps_visitor/container.rb +164 -0
- data/lib/postsvg/visitors/ps_visitor/control_flow.rb +110 -0
- data/lib/postsvg/visitors/ps_visitor/device.rb +20 -0
- data/lib/postsvg/visitors/ps_visitor/dictionary.rb +89 -0
- data/lib/postsvg/visitors/ps_visitor/font.rb +93 -0
- data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +55 -0
- data/lib/postsvg/visitors/ps_visitor/painting.rb +90 -0
- data/lib/postsvg/visitors/ps_visitor/path.rb +112 -0
- data/lib/postsvg/visitors/ps_visitor/stack.rb +47 -0
- data/lib/postsvg/visitors/ps_visitor/transformations.rb +101 -0
- data/lib/postsvg/visitors/ps_visitor.rb +208 -0
- data/lib/postsvg/visitors.rb +9 -0
- data/lib/postsvg.rb +93 -59
- data/lychee.toml +86 -0
- metadata +216 -11
- data/postsvg.gemspec +0 -38
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
= Advanced Topics
|
|
2
|
+
:page-nav_order: 7
|
|
3
|
+
|
|
4
|
+
== Purpose
|
|
5
|
+
|
|
6
|
+
This section covers advanced Postsvg usage patterns, optimization techniques, and complex scenarios. These topics are intended for users who need to extend Postsvg, integrate it into complex workflows, or handle edge cases.
|
|
7
|
+
|
|
8
|
+
== References
|
|
9
|
+
|
|
10
|
+
* link:index.adoc[Documentation Home]
|
|
11
|
+
* link:api-reference.adoc[API Reference]
|
|
12
|
+
* link:architecture.adoc[Architecture Documentation]
|
|
13
|
+
* link:development.adoc[Development Guide]
|
|
14
|
+
|
|
15
|
+
== Concepts
|
|
16
|
+
|
|
17
|
+
**Strict Mode**:: A validation mode that fails on unknown or unsupported operators.
|
|
18
|
+
|
|
19
|
+
**BoundingBox Handling**:: Extracting and applying document dimensions from PostScript comments.
|
|
20
|
+
|
|
21
|
+
**Custom Operators**:: Extending Postsvg with custom PostScript operator implementations.
|
|
22
|
+
|
|
23
|
+
**Error Recovery**:: Strategies for handling malformed or partially valid PostScript files.
|
|
24
|
+
|
|
25
|
+
**Optimization Techniques**:: Methods for improving conversion performance and output quality.
|
|
26
|
+
|
|
27
|
+
== Advanced Topics
|
|
28
|
+
|
|
29
|
+
link:advanced-topics/custom-operators.adoc[**Custom Operators**]::
|
|
30
|
+
How to extend Postsvg by implementing custom PostScript operators.
|
|
31
|
+
|
|
32
|
+
link:advanced-topics/strict-mode.adoc[**Strict Mode**]::
|
|
33
|
+
Enable strict validation to catch unknown operators and ensure complete PostScript support.
|
|
34
|
+
|
|
35
|
+
link:advanced-topics/bounding-box-handling.adoc[**BoundingBox Handling**]::
|
|
36
|
+
Extract, validate, and apply BoundingBox information for proper SVG dimensions.
|
|
37
|
+
|
|
38
|
+
link:advanced-topics/error-handling.adoc[**Error Handling**]::
|
|
39
|
+
Strategies for handling conversion errors, validation failures, and partial conversions.
|
|
40
|
+
|
|
41
|
+
link:advanced-topics/memory-considerations.adoc[**Memory Considerations**]::
|
|
42
|
+
Handling large PostScript files, memory optimization, and batch processing strategies.
|
|
43
|
+
|
|
44
|
+
link:advanced-topics/compatibility.adoc[**ps2svg Compatibility**]::
|
|
45
|
+
Compatibility notes, differences, and migration guide from ps2svg.
|
|
46
|
+
|
|
47
|
+
== Strict Mode
|
|
48
|
+
|
|
49
|
+
Strict mode causes Postsvg to fail immediately when encountering unknown operators:
|
|
50
|
+
|
|
51
|
+
[source,ruby]
|
|
52
|
+
----
|
|
53
|
+
# Enable strict mode
|
|
54
|
+
converter = Postsvg::Converter.new(
|
|
55
|
+
ps_content,
|
|
56
|
+
strict_mode: true
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
begin
|
|
60
|
+
svg = converter.convert
|
|
61
|
+
rescue Postsvg::Error => e
|
|
62
|
+
puts "Unknown operator: #{e.message}"
|
|
63
|
+
end
|
|
64
|
+
----
|
|
65
|
+
|
|
66
|
+
**Use Cases:**
|
|
67
|
+
* Development and testing
|
|
68
|
+
* Ensuring complete PostScript support
|
|
69
|
+
* Validating operator coverage
|
|
70
|
+
* Debugging conversion issues
|
|
71
|
+
|
|
72
|
+
**Trade-offs:**
|
|
73
|
+
* May fail on harmless unsupported operators
|
|
74
|
+
* More verbose error handling required
|
|
75
|
+
* Not suitable for production with varied input
|
|
76
|
+
|
|
77
|
+
== Custom Operator Implementation
|
|
78
|
+
|
|
79
|
+
.Implementing a custom operator
|
|
80
|
+
[example]
|
|
81
|
+
====
|
|
82
|
+
[source,ruby]
|
|
83
|
+
----
|
|
84
|
+
module Postsvg
|
|
85
|
+
module Commands
|
|
86
|
+
class CustomRect < Base
|
|
87
|
+
def execute(context)
|
|
88
|
+
# Pop arguments: width height x y
|
|
89
|
+
height = context.pop_number
|
|
90
|
+
width = context.pop_number
|
|
91
|
+
y = context.pop_number
|
|
92
|
+
x = context.pop_number
|
|
93
|
+
|
|
94
|
+
# Draw rectangle using existing operators
|
|
95
|
+
context.graphics_state.newpath
|
|
96
|
+
context.graphics_state.moveto(x, y)
|
|
97
|
+
context.graphics_state.lineto(x + width, y)
|
|
98
|
+
context.graphics_state.lineto(x + width, y + height)
|
|
99
|
+
context.graphics_state.lineto(x, y + height)
|
|
100
|
+
context.graphics_state.closepath
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Register custom operator
|
|
107
|
+
Postsvg::Commands::Registry.register('customrect',
|
|
108
|
+
Postsvg::Commands::CustomRect.new)
|
|
109
|
+
----
|
|
110
|
+
|
|
111
|
+
This implements a `customrect` operator that takes four arguments (x, y, width, height) and constructs a rectangular path.
|
|
112
|
+
====
|
|
113
|
+
|
|
114
|
+
== BoundingBox Extraction
|
|
115
|
+
|
|
116
|
+
PostScript files may contain BoundingBox comments in different formats:
|
|
117
|
+
|
|
118
|
+
[source,postscript]
|
|
119
|
+
----
|
|
120
|
+
%%BoundingBox: 0 0 612 792 # Standard
|
|
121
|
+
%%BoundingBox: (atend) # Deferred
|
|
122
|
+
%%HiResBoundingBox: 0 0 612.5 792.5 # High resolution
|
|
123
|
+
----
|
|
124
|
+
|
|
125
|
+
Postsvg handles BoundingBox extraction:
|
|
126
|
+
|
|
127
|
+
[source,ruby]
|
|
128
|
+
----
|
|
129
|
+
# Automatic extraction
|
|
130
|
+
converter = Postsvg::Converter.new(ps_content)
|
|
131
|
+
svg = converter.convert # Uses extracted BoundingBox
|
|
132
|
+
|
|
133
|
+
# Manual override
|
|
134
|
+
bbox = { llx: 0, lly: 0, urx: 100, ury: 100,
|
|
135
|
+
width: 100, height: 100 }
|
|
136
|
+
interpreter = Postsvg::Interpreter.new
|
|
137
|
+
result = interpreter.interpret(tokens, bbox)
|
|
138
|
+
----
|
|
139
|
+
|
|
140
|
+
**Fallback Behavior:**
|
|
141
|
+
If no BoundingBox is found, Postsvg defaults to 1920x1080 (Full HD).
|
|
142
|
+
|
|
143
|
+
== Error Recovery Strategies
|
|
144
|
+
|
|
145
|
+
=== Graceful Degradation
|
|
146
|
+
|
|
147
|
+
[source,ruby]
|
|
148
|
+
----
|
|
149
|
+
def safe_convert(ps_files)
|
|
150
|
+
results = []
|
|
151
|
+
|
|
152
|
+
ps_files.each do |file|
|
|
153
|
+
begin
|
|
154
|
+
# Try strict conversion first
|
|
155
|
+
converter = Postsvg::Converter.new(
|
|
156
|
+
File.read(file),
|
|
157
|
+
strict_mode: true
|
|
158
|
+
)
|
|
159
|
+
svg = converter.convert
|
|
160
|
+
results << { file: file, status: :success, svg: svg }
|
|
161
|
+
rescue Postsvg::Error => e
|
|
162
|
+
# Fall back to lenient mode
|
|
163
|
+
converter = Postsvg::Converter.new(
|
|
164
|
+
File.read(file),
|
|
165
|
+
strict_mode: false
|
|
166
|
+
)
|
|
167
|
+
begin
|
|
168
|
+
svg = converter.convert
|
|
169
|
+
results << {
|
|
170
|
+
file: file,
|
|
171
|
+
status: :partial,
|
|
172
|
+
svg: svg,
|
|
173
|
+
warning: e.message
|
|
174
|
+
}
|
|
175
|
+
rescue StandardError => e2
|
|
176
|
+
results << {
|
|
177
|
+
file: file,
|
|
178
|
+
status: :failed,
|
|
179
|
+
error: e2.message
|
|
180
|
+
}
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
results
|
|
186
|
+
end
|
|
187
|
+
----
|
|
188
|
+
|
|
189
|
+
=== Validation Before Conversion
|
|
190
|
+
|
|
191
|
+
[source,ruby]
|
|
192
|
+
----
|
|
193
|
+
require 'postsvg'
|
|
194
|
+
|
|
195
|
+
# Validate first
|
|
196
|
+
validation = Postsvg::Services::ValidationService.new(
|
|
197
|
+
ps_content,
|
|
198
|
+
'file.ps',
|
|
199
|
+
level: :semantic
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
result = validation.validate
|
|
203
|
+
|
|
204
|
+
if result.valid?
|
|
205
|
+
# Safe to convert
|
|
206
|
+
svg = Postsvg.convert(ps_content)
|
|
207
|
+
else
|
|
208
|
+
# Handle errors
|
|
209
|
+
puts "Validation errors:"
|
|
210
|
+
result.errors.each { |e| puts " - #{e}" }
|
|
211
|
+
end
|
|
212
|
+
----
|
|
213
|
+
|
|
214
|
+
== Memory Optimization
|
|
215
|
+
|
|
216
|
+
For large files or batch processing:
|
|
217
|
+
|
|
218
|
+
=== Streaming Approach
|
|
219
|
+
|
|
220
|
+
[source,ruby]
|
|
221
|
+
----
|
|
222
|
+
# Process files one at a time
|
|
223
|
+
Dir.glob('*.ps').each do |file|
|
|
224
|
+
ps_content = File.read(file)
|
|
225
|
+
svg = Postsvg.convert(ps_content)
|
|
226
|
+
File.write(file.sub('.ps', '.svg'), svg)
|
|
227
|
+
|
|
228
|
+
# Explicitly clear
|
|
229
|
+
ps_content = nil
|
|
230
|
+
svg = nil
|
|
231
|
+
GC.start
|
|
232
|
+
end
|
|
233
|
+
----
|
|
234
|
+
|
|
235
|
+
=== Batch Size Limiting
|
|
236
|
+
|
|
237
|
+
[source,ruby]
|
|
238
|
+
----
|
|
239
|
+
# Process in batches
|
|
240
|
+
files = Dir.glob('*.ps')
|
|
241
|
+
batch_size = 10
|
|
242
|
+
|
|
243
|
+
files.each_slice(batch_size) do |batch|
|
|
244
|
+
threads = batch.map do |file|
|
|
245
|
+
Thread.new do
|
|
246
|
+
Postsvg.convert_file(file, file.sub('.ps', '.svg'))
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
threads.each(&:join)
|
|
251
|
+
GC.start # Clean up between batches
|
|
252
|
+
end
|
|
253
|
+
----
|
|
254
|
+
|
|
255
|
+
== Advanced Validation
|
|
256
|
+
|
|
257
|
+
=== Custom Validation Rules
|
|
258
|
+
|
|
259
|
+
[source,ruby]
|
|
260
|
+
----
|
|
261
|
+
# Validate specific features
|
|
262
|
+
class CustomValidator
|
|
263
|
+
def initialize(ps_content)
|
|
264
|
+
@content = ps_content
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def validate_encoding
|
|
268
|
+
# Check for specific encoding
|
|
269
|
+
@content.match?(/%!PS-Adobe-3\.0/)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def validate_fonts
|
|
273
|
+
# Ensure no font operations
|
|
274
|
+
!@content.match?(/\b(findfont|setfont|show)\b/)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def validate_images
|
|
278
|
+
# Ensure no image operations
|
|
279
|
+
!@content.match?(/\b(image|imagemask)\b/)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
validator = CustomValidator.new(ps_content)
|
|
284
|
+
puts "Valid encoding: #{validator.validate_encoding}"
|
|
285
|
+
puts "No fonts: #{validator.validate_fonts}"
|
|
286
|
+
puts "No images: #{validator.validate_images}"
|
|
287
|
+
----
|
|
288
|
+
|
|
289
|
+
== Performance Profiling
|
|
290
|
+
|
|
291
|
+
[source,ruby]
|
|
292
|
+
----
|
|
293
|
+
require 'benchmark'
|
|
294
|
+
require 'postsvg'
|
|
295
|
+
|
|
296
|
+
ps_content = File.read('large_file.ps')
|
|
297
|
+
|
|
298
|
+
time = Benchmark.measure do
|
|
299
|
+
svg = Postsvg.convert(ps_content)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
puts "Conversion time: #{time.real}s"
|
|
303
|
+
puts "Memory used: #{GC.stat[:total_allocated_objects]} objects"
|
|
304
|
+
----
|
|
305
|
+
|
|
306
|
+
== Integration Patterns
|
|
307
|
+
|
|
308
|
+
=== Rails Integration
|
|
309
|
+
|
|
310
|
+
[source,ruby]
|
|
311
|
+
----
|
|
312
|
+
# app/services/postscript_converter.rb
|
|
313
|
+
class PostscriptConverter
|
|
314
|
+
def self.convert(uploaded_file)
|
|
315
|
+
ps_content = uploaded_file.read
|
|
316
|
+
|
|
317
|
+
svg = Postsvg.convert(ps_content)
|
|
318
|
+
|
|
319
|
+
# Store SVG
|
|
320
|
+
svg_file = Tempfile.new(['converted', '.svg'])
|
|
321
|
+
svg_file.write(svg)
|
|
322
|
+
svg_file.rewind
|
|
323
|
+
|
|
324
|
+
svg_file
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# In controller
|
|
329
|
+
class DocumentsController < ApplicationController
|
|
330
|
+
def convert
|
|
331
|
+
ps_file = params[:file]
|
|
332
|
+
svg_file = PostscriptConverter.convert(ps_file)
|
|
333
|
+
|
|
334
|
+
send_file svg_file.path,
|
|
335
|
+
filename: 'converted.svg',
|
|
336
|
+
type: 'image/svg+xml'
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
----
|
|
340
|
+
|
|
341
|
+
=== Rake Task Integration
|
|
342
|
+
|
|
343
|
+
[source,ruby]
|
|
344
|
+
----
|
|
345
|
+
# lib/tasks/convert.rake
|
|
346
|
+
namespace :postscript do
|
|
347
|
+
desc "Convert all PS files to SVG"
|
|
348
|
+
task :convert => :environment do
|
|
349
|
+
Dir.glob(Rails.root.join('public', 'ps', '*.ps')).each do |file|
|
|
350
|
+
output = file.sub('.ps', '.svg')
|
|
351
|
+
Postsvg.convert_file(file, output)
|
|
352
|
+
puts "Converted #{File.basename(file)}"
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
----
|
|
357
|
+
|
|
358
|
+
== Next Steps
|
|
359
|
+
|
|
360
|
+
* Explore link:development.adoc[Development Guide] for extending Postsvg
|
|
361
|
+
* Review link:architecture.adoc[Architecture] for implementation details
|
|
362
|
+
* Check link:troubleshooting.adoc[Troubleshooting] for common issues
|
|
363
|
+
* See link:api-reference.adoc[API Reference] for detailed method documentation
|
|
364
|
+
|
|
365
|
+
== Bibliography
|
|
366
|
+
|
|
367
|
+
* link:advanced-topics/custom-operators.adoc[Custom Operators Guide]
|
|
368
|
+
* link:advanced-topics/strict-mode.adoc[Strict Mode Documentation]
|
|
369
|
+
* link:advanced-topics/error-handling.adoc[Error Handling Strategies]
|
|
370
|
+
* link:https://www.adobe.com/products/postscript/pdfs/PLRM.pdf[PostScript Language Reference]
|