postsvg 0.1.0 → 0.2.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.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +533 -49
  3. data/CHANGELOG.md +105 -0
  4. data/CLAUDE.md +173 -0
  5. data/Gemfile +2 -3
  6. data/README.adoc +456 -179
  7. data/Rakefile +100 -0
  8. data/TODO.roadmap/00-architecture.md +139 -0
  9. data/TODO.roadmap/01-autoload-migration.md +39 -0
  10. data/TODO.roadmap/02-isolate-dormant-code.md +51 -0
  11. data/TODO.roadmap/03-domain-model.md +66 -0
  12. data/TODO.roadmap/04-lexer.md +40 -0
  13. data/TODO.roadmap/05-parser.md +43 -0
  14. data/TODO.roadmap/06-graphics-state.md +45 -0
  15. data/TODO.roadmap/07-matrix-and-color.md +37 -0
  16. data/TODO.roadmap/08-svg-builder.md +51 -0
  17. data/TODO.roadmap/09-renderer.md +52 -0
  18. data/TODO.roadmap/10-visitor.md +58 -0
  19. data/TODO.roadmap/11-operator-coverage.md +103 -0
  20. data/TODO.roadmap/12-svg-domain.md +62 -0
  21. data/TODO.roadmap/13-translation-handlers.md +69 -0
  22. data/TODO.roadmap/14-ps-serializer.md +49 -0
  23. data/TODO.roadmap/15-cli-and-public-api.md +47 -0
  24. data/TODO.roadmap/16-specs.md +84 -0
  25. data/TODO.roadmap/17-docs-sync.md +47 -0
  26. data/TODO.roadmap/18-performance-and-determinism.md +47 -0
  27. data/TODO.roadmap/19-error-model.md +45 -0
  28. data/TODO.roadmap/20-font-and-text.md +46 -0
  29. data/TODO.roadmap/21-images.md +45 -0
  30. data/TODO.roadmap/22-forms-and-resources.md +25 -0
  31. data/TODO.roadmap/23-level2-level3.md +52 -0
  32. data/TODO.roadmap/24-ci-and-release.md +42 -0
  33. data/TODO.roadmap/README.md +77 -0
  34. data/docs/.gitignore +29 -0
  35. data/docs/CHANGELOG.md +114 -0
  36. data/docs/COMPLETE_DOCUMENTATION_STATUS.md +376 -0
  37. data/docs/DEPLOYMENT.md +456 -0
  38. data/docs/DEPLOYMENT_INSTRUCTIONS.md +229 -0
  39. data/docs/DOCUMENTATION_PLAN.md +425 -0
  40. data/docs/FINAL_SUMMARY.md +657 -0
  41. data/docs/Gemfile +15 -0
  42. data/docs/README.md +327 -0
  43. data/docs/_config.yml +99 -0
  44. data/docs/advanced-topics.adoc +370 -0
  45. data/docs/api-reference/colors.adoc +705 -0
  46. data/docs/api-reference/converter.adoc +699 -0
  47. data/docs/api-reference/execution-context.adoc +1210 -0
  48. data/docs/api-reference/graphics-state.adoc +1070 -0
  49. data/docs/api-reference/interpreter.adoc +810 -0
  50. data/docs/api-reference/matrix.adoc +1179 -0
  51. data/docs/api-reference/path-builder.adoc +1284 -0
  52. data/docs/api-reference/postsvg-module.adoc +388 -0
  53. data/docs/api-reference/svg-generator.adoc +891 -0
  54. data/docs/api-reference/tokenizer.adoc +925 -0
  55. data/docs/api-reference.adoc +221 -0
  56. data/docs/architecture/command-registry.adoc +1191 -0
  57. data/docs/architecture/conversion-pipeline.adoc +746 -0
  58. data/docs/architecture/design-decisions.adoc +999 -0
  59. data/docs/architecture/generator-stage.adoc +1115 -0
  60. data/docs/architecture/graphics-state-model.adoc +1089 -0
  61. data/docs/architecture/interpreter-stage.adoc +1125 -0
  62. data/docs/architecture/parser-stage.adoc +1051 -0
  63. data/docs/architecture.adoc +354 -0
  64. data/docs/cli-reference/batch-command.adoc +616 -0
  65. data/docs/cli-reference/check-command.adoc +677 -0
  66. data/docs/cli-reference/cli-options.adoc +802 -0
  67. data/docs/cli-reference/convert-command.adoc +462 -0
  68. data/docs/cli-reference/version-command.adoc +296 -0
  69. data/docs/cli-reference.adoc +317 -0
  70. data/docs/concepts/conversion-pipeline.adoc +903 -0
  71. data/docs/concepts/coordinate-systems.adoc +836 -0
  72. data/docs/concepts/graphics-state.adoc +861 -0
  73. data/docs/concepts/path-operations.adoc +1076 -0
  74. data/docs/concepts/postscript-language.adoc +859 -0
  75. data/docs/concepts/svg-generation.adoc +937 -0
  76. data/docs/concepts.adoc +198 -0
  77. data/docs/contributing.adoc +443 -0
  78. data/docs/development.adoc +420 -0
  79. data/docs/faq.adoc +493 -0
  80. data/docs/getting-started/basic-usage.adoc +538 -0
  81. data/docs/getting-started/common-workflows.adoc +577 -0
  82. data/docs/getting-started/first-conversion.adoc +492 -0
  83. data/docs/getting-started/installation.adoc +534 -0
  84. data/docs/getting-started.adoc +94 -0
  85. data/docs/index.adoc +248 -0
  86. data/docs/optimization.adoc +196 -0
  87. data/docs/ps2svg_compatibility.adoc +149 -0
  88. data/docs/quick-reference.adoc +453 -0
  89. data/docs/sitemap.adoc +337 -0
  90. data/docs/troubleshooting.adoc +486 -0
  91. data/docs/validation.adoc +772 -0
  92. data/exe/postsvg +1 -0
  93. data/lib/postsvg/cli.rb +109 -57
  94. data/lib/postsvg/errors.rb +68 -3
  95. data/lib/postsvg/graphics_context.rb +81 -0
  96. data/lib/postsvg/graphics_stack.rb +43 -0
  97. data/lib/postsvg/options.rb +29 -0
  98. data/lib/postsvg/parser/postscript_parser.rb +7 -7
  99. data/lib/postsvg/renderer.rb +89 -0
  100. data/lib/postsvg/svg/attribute_parser.rb +45 -0
  101. data/lib/postsvg/svg/clip_path_registry.rb +46 -0
  102. data/lib/postsvg/svg/document.rb +22 -0
  103. data/lib/postsvg/svg/element.rb +86 -0
  104. data/lib/postsvg/svg/elements/circle.rb +36 -0
  105. data/lib/postsvg/svg/elements/clip_path.rb +26 -0
  106. data/lib/postsvg/svg/elements/defs.rb +24 -0
  107. data/lib/postsvg/svg/elements/ellipse.rb +39 -0
  108. data/lib/postsvg/svg/elements/group.rb +37 -0
  109. data/lib/postsvg/svg/elements/image.rb +35 -0
  110. data/lib/postsvg/svg/elements/line.rb +36 -0
  111. data/lib/postsvg/svg/elements/path.rb +32 -0
  112. data/lib/postsvg/svg/elements/polygon.rb +12 -0
  113. data/lib/postsvg/svg/elements/polyline.rb +32 -0
  114. data/lib/postsvg/svg/elements/rect.rb +44 -0
  115. data/lib/postsvg/svg/elements/svg.rb +40 -0
  116. data/lib/postsvg/svg/elements/text.rb +42 -0
  117. data/lib/postsvg/svg/elements.rb +31 -0
  118. data/lib/postsvg/svg/paint.rb +34 -0
  119. data/lib/postsvg/svg/parser.rb +39 -0
  120. data/lib/postsvg/svg/path_data/command.rb +27 -0
  121. data/lib/postsvg/svg/path_data/parser.rb +86 -0
  122. data/lib/postsvg/svg/path_data.rb +17 -0
  123. data/lib/postsvg/svg/stroke.rb +33 -0
  124. data/lib/postsvg/svg/transform_list.rb +59 -0
  125. data/lib/postsvg/svg.rb +22 -0
  126. data/lib/postsvg/svg_builder.rb +253 -0
  127. data/lib/postsvg/translation/arc_converter.rb +96 -0
  128. data/lib/postsvg/translation/bounding_box.rb +62 -0
  129. data/lib/postsvg/translation/context.rb +34 -0
  130. data/lib/postsvg/translation/handler_registry.rb +38 -0
  131. data/lib/postsvg/translation/handlers/circle_handler.rb +28 -0
  132. data/lib/postsvg/translation/handlers/clip_path_handler.rb +13 -0
  133. data/lib/postsvg/translation/handlers/defs_handler.rb +15 -0
  134. data/lib/postsvg/translation/handlers/ellipse_handler.rb +36 -0
  135. data/lib/postsvg/translation/handlers/group_handler.rb +22 -0
  136. data/lib/postsvg/translation/handlers/image_handler.rb +21 -0
  137. data/lib/postsvg/translation/handlers/line_handler.rb +27 -0
  138. data/lib/postsvg/translation/handlers/open_handler.rb +19 -0
  139. data/lib/postsvg/translation/handlers/path_handler.rb +372 -0
  140. data/lib/postsvg/translation/handlers/polygon_handler.rb +35 -0
  141. data/lib/postsvg/translation/handlers/polyline_handler.rb +33 -0
  142. data/lib/postsvg/translation/handlers/rect_handler.rb +32 -0
  143. data/lib/postsvg/translation/handlers/shared.rb +110 -0
  144. data/lib/postsvg/translation/handlers/svg_handler.rb +26 -0
  145. data/lib/postsvg/translation/handlers/text_handler.rb +57 -0
  146. data/lib/postsvg/translation/handlers.rb +26 -0
  147. data/lib/postsvg/translation/ps_renderer.rb +106 -0
  148. data/lib/postsvg/translation/record_emitter.rb +35 -0
  149. data/lib/postsvg/translation.rb +17 -0
  150. data/lib/postsvg/version.rb +1 -1
  151. data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +125 -0
  152. data/lib/postsvg/visitors/ps_visitor/boolean.rb +105 -0
  153. data/lib/postsvg/visitors/ps_visitor/color.rb +56 -0
  154. data/lib/postsvg/visitors/ps_visitor/common.rb +65 -0
  155. data/lib/postsvg/visitors/ps_visitor/container.rb +164 -0
  156. data/lib/postsvg/visitors/ps_visitor/control_flow.rb +110 -0
  157. data/lib/postsvg/visitors/ps_visitor/device.rb +20 -0
  158. data/lib/postsvg/visitors/ps_visitor/dictionary.rb +93 -0
  159. data/lib/postsvg/visitors/ps_visitor/font.rb +103 -0
  160. data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +55 -0
  161. data/lib/postsvg/visitors/ps_visitor/painting.rb +90 -0
  162. data/lib/postsvg/visitors/ps_visitor/path.rb +117 -0
  163. data/lib/postsvg/visitors/ps_visitor/stack.rb +47 -0
  164. data/lib/postsvg/visitors/ps_visitor/transformations.rb +101 -0
  165. data/lib/postsvg/visitors/ps_visitor.rb +208 -0
  166. data/lib/postsvg/visitors.rb +9 -0
  167. data/lib/postsvg.rb +96 -57
  168. data/lychee.toml +86 -0
  169. metadata +197 -12
  170. data/lib/postsvg/matrix.rb +0 -106
  171. data/postsvg.gemspec +0 -38
data/lib/postsvg.rb CHANGED
@@ -1,78 +1,117 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "postsvg/version"
4
- require_relative "postsvg/errors"
5
- require_relative "postsvg/tokenizer"
6
- require_relative "postsvg/interpreter"
3
+ require "postscript"
4
+ require "parslet"
5
+ require "thor"
6
+ require "nokogiri"
7
7
 
8
8
  module Postsvg
9
- class << self
10
- # Convert PostScript content to SVG
11
- def convert(ps_content)
12
- bbox = extract_bounding_box(ps_content)
13
- tokens = Tokenizer.tokenize(ps_content)
9
+ autoload :VERSION, "postsvg/version"
14
10
 
15
- interpreter = Interpreter.new
16
- svg_out = interpreter.interpret(tokens, bbox)
11
+ # ============================================================
12
+ # Posts created and managed by the +postscript+ gem.
13
+ # ============================================================
14
+ #
15
+ # `postscript` owns PS source parsing, the typed PS domain model,
16
+ # and the PS source serializer. The `Postscript` namespace is the
17
+ # canonical location; the aliases below keep existing user code
18
+ # working during the transition (deprecated, will be removed at
19
+ # postsvg 1.0).
20
+ #
21
+ # If you maintain postsvg, prefer `Postscript::*` in new code.
17
22
 
18
- generate_svg(svg_out, bbox)
19
- end
23
+ Source = Postscript::Source
24
+ Model = Postscript::Model
25
+ Serializer = Postscript::Serializer
26
+ Matrix = Postscript::Matrix
27
+ Color = Postscript::Color
28
+ FormatNumber = Postscript::FormatNumber
20
29
 
21
- # Convert PostScript file to SVG
22
- def convert_file(input_path, output_path = nil)
23
- ps_content = File.read(input_path)
24
- svg_content = convert(ps_content)
30
+ ParseError = Postscript::ParseError
31
+ LexError = Postscript::LexError
32
+ SyntaxError = Postscript::SyntaxError
33
+ StackUnderflowError = Postscript::StackUnderflowError
34
+ UndefinedOperatorError = Postscript::UndefinedOperatorError
35
+ RecursionLimitError = Postscript::RecursionLimitError
36
+ RenderError = Postscript::RenderError
37
+ SerializeError = Postscript::SerializeError
38
+ ExitSignal = Postscript::ExitSignal
39
+ QuitSignal = Postscript::QuitSignal
25
40
 
26
- File.write(output_path, svg_content) if output_path
41
+ # ============================================================
42
+ # Errors that originate in the SVG side (kept here, not in postscript).
43
+ # ============================================================
44
+ autoload :Error, "postsvg/errors"
45
+ autoload :TranslationError, "postsvg/errors"
46
+ autoload :UnsupportedElementError, "postsvg/errors"
47
+ autoload :UnresolvedReferenceError, "postsvg/errors"
27
48
 
28
- svg_content
29
- end
49
+ # Legacy alias for RenderError (postsvg 0.1 API).
50
+ ConversionError = RenderError
51
+ # Legacy alias for UndefinedOperatorError (postsvg 0.1 API).
52
+ UnsupportedOperatorError = UndefinedOperatorError
30
53
 
31
- private
54
+ # ============================================================
55
+ # Rendering / SVG-side types owned by postsvg.
56
+ # ============================================================
57
+ autoload :GraphicsContext, "postsvg/graphics_context"
58
+ autoload :GraphicsStack, "postsvg/graphics_stack"
59
+ autoload :PathBuilder, "postsvg/path_builder"
60
+ autoload :SvgBuilder, "postsvg/svg_builder"
61
+ autoload :Options, "postsvg/options"
62
+ autoload :Renderer, "postsvg/renderer"
63
+ autoload :Visitors, "postsvg/visitors"
64
+ autoload :Svg, "postsvg/svg"
65
+ autoload :Translation, "postsvg/translation"
66
+ autoload :CLI, "postsvg/cli"
32
67
 
33
- def extract_bounding_box(ps_content)
34
- match = ps_content.match(/%%BoundingBox:\s*([-+0-9.eE]+)\s+([-+0-9.eE]+)\s+([-+0-9.eE]+)\s+([-+0-9.eE]+)/)
35
- return nil unless match
68
+ # Legacy implementations retained on disk for reference. Not on the
69
+ # public autoload path; require explicitly if needed:
70
+ # require "postsvg/tokenizer"
71
+ # require "postsvg/interpreter"
72
+ # require "postsvg/parser"
73
+ # require "postsvg/converter"
74
+ # require "postsvg/svg_generator"
75
+ # require "postsvg/graphics_state"
76
+ # require "postsvg/colors"
36
77
 
37
- {
38
- llx: match[1].to_f,
39
- lly: match[2].to_f,
40
- urx: match[3].to_f,
41
- ury: match[4].to_f,
42
- }
78
+ class << self
79
+ # PS/EPS source -> SVG string.
80
+ def to_svg(source, **options)
81
+ program = Postscript::Source.parse(source)
82
+ Renderer.call(program, Options.new(**options))
43
83
  end
44
84
 
45
- def generate_svg(svg_out, bbox)
46
- if bbox
47
- width = bbox[:urx] - bbox[:llx]
48
- height = bbox[:ury] - bbox[:lly]
49
- view_box = "viewBox=\"#{num_fmt(bbox[:llx])} #{num_fmt(bbox[:lly])} #{num_fmt(width)} #{num_fmt(height)}\" " \
50
- "width=\"#{num_fmt(width)}\" height=\"#{num_fmt(height)}\""
51
- else
52
- width = 1920
53
- height = 1080
54
- view_box = "viewBox=\"0 0 #{width} #{height}\" width=\"#{width}\" height=\"#{height}\""
55
- end
85
+ # PS/EPS file -> SVG string. Writes to +output_path+ if given;
86
+ # returns the SVG string either way.
87
+ def to_svg_file(input_path, output_path = nil, **options)
88
+ svg = to_svg(File.read(input_path), **options)
89
+ File.write(output_path, svg) if output_path
90
+ svg
91
+ end
56
92
 
57
- defs = svg_out[:defs].empty? ? "" : "<defs>\n#{svg_out[:defs].join("\n")}\n</defs>"
58
- shapes = svg_out[:element_shapes].join("\n")
59
- texts = svg_out[:element_texts].join("\n")
60
- body = "<g transform=\"translate(0 #{height}) scale(1 -1)\">\n#{shapes}\n#{texts}</g>"
93
+ # SVG string -> PS source. Pass +eps: true+ for EPS output.
94
+ def to_ps(svg_string, eps: false, **options)
95
+ document = Svg::Parser.call(svg_string)
96
+ program = Translation::PsRenderer.call(document, eps: eps)
97
+ Serializer.call(program, eps: eps, **options)
98
+ end
61
99
 
62
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
63
- "<svg xmlns=\"http://www.w3.org/2000/svg\" #{view_box}>\n" \
64
- "#{defs}\n" \
65
- "#{body}\n" \
66
- "</svg>"
100
+ # SVG string -> EPS source.
101
+ def to_eps(svg_string, **options)
102
+ to_ps(svg_string, eps: true, **options)
67
103
  end
68
104
 
69
- def num_fmt(n)
70
- # Format number, removing unnecessary decimals
71
- if n == n.to_i
72
- n.to_i.to_s
73
- else
74
- format("%.3f", n).sub(/\.?0+$/, "")
75
- end
105
+ # SVG file -> PS source. Writes to +output_path+ if given.
106
+ def to_ps_file(input_path, output_path = nil, eps: false, **options)
107
+ ps = to_ps(File.read(input_path), eps: eps, **options)
108
+ File.write(output_path, ps) if output_path
109
+ ps
76
110
  end
111
+
112
+ # Backwards-compatible aliases. Pre-0.2 the only direction was
113
+ # PS -> SVG; existing callers used +convert+ / +convert_file+.
114
+ alias convert to_svg
115
+ alias convert_file to_svg_file
77
116
  end
78
117
  end
data/lychee.toml ADDED
@@ -0,0 +1,86 @@
1
+ # Lychee link checker configuration for Postsvg documentation
2
+ # https://lychee.cli.rs/
3
+ #
4
+ # This configuration is optimized for checking internal documentation links.
5
+ # External URLs are excluded by default to avoid false positives from
6
+ # anti-bot measures and rate limiting.
7
+
8
+ # Base configuration
9
+ max_redirects = 10
10
+ max_retries = 3
11
+ timeout = 20
12
+
13
+ # Check files matching these patterns
14
+ include = [
15
+ "docs/**/*.adoc",
16
+ "README.adoc"
17
+ ]
18
+
19
+ # Exclude certain patterns from checking (regex patterns)
20
+ exclude = [
21
+ # Exclude generated/temporary files
22
+ "docs/docs/.*",
23
+ ".*/node_modules/.*",
24
+ ".*/.git/.*"
25
+ ]
26
+
27
+ # Exclude certain link patterns
28
+ exclude_link_local = false
29
+ exclude_all_private = false
30
+ exclude_mail = false
31
+
32
+ # Accept status codes as valid
33
+ accept = [
34
+ 200, 201, 202, 203, 204, 205, 206, # 2xx success
35
+ 300, 301, 302, 303, 307, 308, # 3xx redirects
36
+ 429 # Rate limit - acceptable for external links
37
+ ]
38
+
39
+ # Include fragments in link validation (e.g., #section-name)
40
+ include_fragments = true
41
+
42
+ # Follow HTTP redirects
43
+ follow_redirects = true
44
+
45
+ # Check for broken fragments (anchor links)
46
+ check_fragments = true
47
+
48
+ # Retry broken links before reporting
49
+ retry_broken = true
50
+
51
+ # Cache successful link checks to speed up repeated runs
52
+ cache = true
53
+
54
+ # User agent string for HTTP requests
55
+ user_agent = "lychee/postsvg-docs"
56
+
57
+ # HTTP method for checking links
58
+ method = "get"
59
+
60
+ # Headers to send with requests
61
+ headers = [
62
+ "accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
63
+ ]
64
+
65
+ # Base URL for relative links (when checking outside of workspace context)
66
+ # base = "https://metanorma.github.io/postsvg/"
67
+
68
+ # Skip checking SSL certificates (not recommended for production)
69
+ insecure = false
70
+
71
+ # Maximum number of concurrent network requests
72
+ max_concurrency = 8
73
+
74
+ # Remap URLs (useful for local development or changed URLs)
75
+ # remap = ["https://old-url.com https://new-url.com"]
76
+
77
+ # Custom glob patterns for AsciiDoc links
78
+ # AsciiDoc uses link:path[text] syntax
79
+ # Lychee should automatically detect these, but we ensure all .adoc files are checked
80
+
81
+ # Output format (compact, detailed, json, markdown)
82
+ # This can be overridden via CLI
83
+ format = "detailed"
84
+
85
+ # Exclude specific domains that may have anti-bot measures
86
+ # exclude_path can be used for this purpose if needed
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postsvg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-19 00:00:00.000000000 Z
11
+ date: 2026-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: parslet
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: postscript
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.2'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: thor
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -39,9 +67,10 @@ dependencies:
39
67
  - !ruby/object:Gem::Version
40
68
  version: '0'
41
69
  description: |
42
- Postsvg provides a pure Ruby library for converting PostScript (PS) and
43
- Encapsulated PostScript (EPS) files to clean,
44
- standards-compliant Scalable Vector Graphics (SVG) format output.
70
+ Postsvg is a pure-Ruby transformer between PostScript (PS) /
71
+ Encapsulated PostScript (EPS) and Scalable Vector Graphics (SVG).
72
+ Both directions are implemented: PS/EPS -> SVG and SVG -> PS/EPS.
73
+ No external tools (Ghostscript, Inkscape) are required.
45
74
  email:
46
75
  - open.source@ribose.com
47
76
  executables:
@@ -51,11 +80,92 @@ extra_rdoc_files: []
51
80
  files:
52
81
  - ".rubocop.yml"
53
82
  - ".rubocop_todo.yml"
83
+ - CHANGELOG.md
84
+ - CLAUDE.md
54
85
  - Gemfile
55
86
  - LICENSE
56
87
  - README.adoc
57
88
  - Rakefile
89
+ - TODO.roadmap/00-architecture.md
90
+ - TODO.roadmap/01-autoload-migration.md
91
+ - TODO.roadmap/02-isolate-dormant-code.md
92
+ - TODO.roadmap/03-domain-model.md
93
+ - TODO.roadmap/04-lexer.md
94
+ - TODO.roadmap/05-parser.md
95
+ - TODO.roadmap/06-graphics-state.md
96
+ - TODO.roadmap/07-matrix-and-color.md
97
+ - TODO.roadmap/08-svg-builder.md
98
+ - TODO.roadmap/09-renderer.md
99
+ - TODO.roadmap/10-visitor.md
100
+ - TODO.roadmap/11-operator-coverage.md
101
+ - TODO.roadmap/12-svg-domain.md
102
+ - TODO.roadmap/13-translation-handlers.md
103
+ - TODO.roadmap/14-ps-serializer.md
104
+ - TODO.roadmap/15-cli-and-public-api.md
105
+ - TODO.roadmap/16-specs.md
106
+ - TODO.roadmap/17-docs-sync.md
107
+ - TODO.roadmap/18-performance-and-determinism.md
108
+ - TODO.roadmap/19-error-model.md
109
+ - TODO.roadmap/20-font-and-text.md
110
+ - TODO.roadmap/21-images.md
111
+ - TODO.roadmap/22-forms-and-resources.md
112
+ - TODO.roadmap/23-level2-level3.md
113
+ - TODO.roadmap/24-ci-and-release.md
114
+ - TODO.roadmap/README.md
115
+ - docs/.gitignore
116
+ - docs/CHANGELOG.md
117
+ - docs/COMPLETE_DOCUMENTATION_STATUS.md
118
+ - docs/DEPLOYMENT.md
119
+ - docs/DEPLOYMENT_INSTRUCTIONS.md
120
+ - docs/DOCUMENTATION_PLAN.md
121
+ - docs/FINAL_SUMMARY.md
122
+ - docs/Gemfile
58
123
  - docs/POSTSCRIPT.adoc
124
+ - docs/README.md
125
+ - docs/_config.yml
126
+ - docs/advanced-topics.adoc
127
+ - docs/api-reference.adoc
128
+ - docs/api-reference/colors.adoc
129
+ - docs/api-reference/converter.adoc
130
+ - docs/api-reference/execution-context.adoc
131
+ - docs/api-reference/graphics-state.adoc
132
+ - docs/api-reference/interpreter.adoc
133
+ - docs/api-reference/matrix.adoc
134
+ - docs/api-reference/path-builder.adoc
135
+ - docs/api-reference/postsvg-module.adoc
136
+ - docs/api-reference/svg-generator.adoc
137
+ - docs/api-reference/tokenizer.adoc
138
+ - docs/architecture.adoc
139
+ - docs/architecture/command-registry.adoc
140
+ - docs/architecture/conversion-pipeline.adoc
141
+ - docs/architecture/design-decisions.adoc
142
+ - docs/architecture/generator-stage.adoc
143
+ - docs/architecture/graphics-state-model.adoc
144
+ - docs/architecture/interpreter-stage.adoc
145
+ - docs/architecture/parser-stage.adoc
146
+ - docs/cli-reference.adoc
147
+ - docs/cli-reference/batch-command.adoc
148
+ - docs/cli-reference/check-command.adoc
149
+ - docs/cli-reference/cli-options.adoc
150
+ - docs/cli-reference/convert-command.adoc
151
+ - docs/cli-reference/version-command.adoc
152
+ - docs/concepts.adoc
153
+ - docs/concepts/conversion-pipeline.adoc
154
+ - docs/concepts/coordinate-systems.adoc
155
+ - docs/concepts/graphics-state.adoc
156
+ - docs/concepts/path-operations.adoc
157
+ - docs/concepts/postscript-language.adoc
158
+ - docs/concepts/svg-generation.adoc
159
+ - docs/contributing.adoc
160
+ - docs/development.adoc
161
+ - docs/faq.adoc
162
+ - docs/getting-started.adoc
163
+ - docs/getting-started/basic-usage.adoc
164
+ - docs/getting-started/common-workflows.adoc
165
+ - docs/getting-started/first-conversion.adoc
166
+ - docs/getting-started/installation.adoc
167
+ - docs/index.adoc
168
+ - docs/optimization.adoc
59
169
  - docs/postscript/fundamentals.adoc
60
170
  - docs/postscript/graphics-model.adoc
61
171
  - docs/postscript/implementation-notes.adoc
@@ -70,31 +180,106 @@ files:
70
180
  - docs/postscript/operators/stack-manipulation.adoc
71
181
  - docs/postscript/operators/transformations.adoc
72
182
  - docs/postscript/svg-mapping.adoc
183
+ - docs/ps2svg_compatibility.adoc
184
+ - docs/quick-reference.adoc
185
+ - docs/sitemap.adoc
186
+ - docs/troubleshooting.adoc
187
+ - docs/validation.adoc
73
188
  - exe/postsvg
74
189
  - lib/postsvg.rb
75
190
  - lib/postsvg/cli.rb
76
191
  - lib/postsvg/colors.rb
77
192
  - lib/postsvg/converter.rb
78
193
  - lib/postsvg/errors.rb
194
+ - lib/postsvg/graphics_context.rb
195
+ - lib/postsvg/graphics_stack.rb
79
196
  - lib/postsvg/graphics_state.rb
80
197
  - lib/postsvg/interpreter.rb
81
- - lib/postsvg/matrix.rb
198
+ - lib/postsvg/options.rb
82
199
  - lib/postsvg/parser.rb
83
200
  - lib/postsvg/parser/postscript_parser.rb
84
201
  - lib/postsvg/parser/transform.rb
85
202
  - lib/postsvg/path_builder.rb
203
+ - lib/postsvg/renderer.rb
204
+ - lib/postsvg/svg.rb
205
+ - lib/postsvg/svg/attribute_parser.rb
206
+ - lib/postsvg/svg/clip_path_registry.rb
207
+ - lib/postsvg/svg/document.rb
208
+ - lib/postsvg/svg/element.rb
209
+ - lib/postsvg/svg/elements.rb
210
+ - lib/postsvg/svg/elements/circle.rb
211
+ - lib/postsvg/svg/elements/clip_path.rb
212
+ - lib/postsvg/svg/elements/defs.rb
213
+ - lib/postsvg/svg/elements/ellipse.rb
214
+ - lib/postsvg/svg/elements/group.rb
215
+ - lib/postsvg/svg/elements/image.rb
216
+ - lib/postsvg/svg/elements/line.rb
217
+ - lib/postsvg/svg/elements/path.rb
218
+ - lib/postsvg/svg/elements/polygon.rb
219
+ - lib/postsvg/svg/elements/polyline.rb
220
+ - lib/postsvg/svg/elements/rect.rb
221
+ - lib/postsvg/svg/elements/svg.rb
222
+ - lib/postsvg/svg/elements/text.rb
223
+ - lib/postsvg/svg/paint.rb
224
+ - lib/postsvg/svg/parser.rb
225
+ - lib/postsvg/svg/path_data.rb
226
+ - lib/postsvg/svg/path_data/command.rb
227
+ - lib/postsvg/svg/path_data/parser.rb
228
+ - lib/postsvg/svg/stroke.rb
229
+ - lib/postsvg/svg/transform_list.rb
230
+ - lib/postsvg/svg_builder.rb
86
231
  - lib/postsvg/svg_generator.rb
87
232
  - lib/postsvg/tokenizer.rb
233
+ - lib/postsvg/translation.rb
234
+ - lib/postsvg/translation/arc_converter.rb
235
+ - lib/postsvg/translation/bounding_box.rb
236
+ - lib/postsvg/translation/context.rb
237
+ - lib/postsvg/translation/handler_registry.rb
238
+ - lib/postsvg/translation/handlers.rb
239
+ - lib/postsvg/translation/handlers/circle_handler.rb
240
+ - lib/postsvg/translation/handlers/clip_path_handler.rb
241
+ - lib/postsvg/translation/handlers/defs_handler.rb
242
+ - lib/postsvg/translation/handlers/ellipse_handler.rb
243
+ - lib/postsvg/translation/handlers/group_handler.rb
244
+ - lib/postsvg/translation/handlers/image_handler.rb
245
+ - lib/postsvg/translation/handlers/line_handler.rb
246
+ - lib/postsvg/translation/handlers/open_handler.rb
247
+ - lib/postsvg/translation/handlers/path_handler.rb
248
+ - lib/postsvg/translation/handlers/polygon_handler.rb
249
+ - lib/postsvg/translation/handlers/polyline_handler.rb
250
+ - lib/postsvg/translation/handlers/rect_handler.rb
251
+ - lib/postsvg/translation/handlers/shared.rb
252
+ - lib/postsvg/translation/handlers/svg_handler.rb
253
+ - lib/postsvg/translation/handlers/text_handler.rb
254
+ - lib/postsvg/translation/ps_renderer.rb
255
+ - lib/postsvg/translation/record_emitter.rb
88
256
  - lib/postsvg/version.rb
89
- - postsvg.gemspec
257
+ - lib/postsvg/visitors.rb
258
+ - lib/postsvg/visitors/ps_visitor.rb
259
+ - lib/postsvg/visitors/ps_visitor/arithmetic.rb
260
+ - lib/postsvg/visitors/ps_visitor/boolean.rb
261
+ - lib/postsvg/visitors/ps_visitor/color.rb
262
+ - lib/postsvg/visitors/ps_visitor/common.rb
263
+ - lib/postsvg/visitors/ps_visitor/container.rb
264
+ - lib/postsvg/visitors/ps_visitor/control_flow.rb
265
+ - lib/postsvg/visitors/ps_visitor/device.rb
266
+ - lib/postsvg/visitors/ps_visitor/dictionary.rb
267
+ - lib/postsvg/visitors/ps_visitor/font.rb
268
+ - lib/postsvg/visitors/ps_visitor/graphics_state.rb
269
+ - lib/postsvg/visitors/ps_visitor/painting.rb
270
+ - lib/postsvg/visitors/ps_visitor/path.rb
271
+ - lib/postsvg/visitors/ps_visitor/stack.rb
272
+ - lib/postsvg/visitors/ps_visitor/transformations.rb
273
+ - lychee.toml
90
274
  - scripts/regenerate_fixtures.rb
91
- homepage: https://github.com/metanorma/postsvg
275
+ homepage: https://github.com/claricle/postsvg
92
276
  licenses:
93
277
  - BSD-2-Clause
94
278
  metadata:
95
- homepage_uri: https://github.com/metanorma/postsvg
96
- source_code_uri: https://github.com/metanorma/postsvg
97
- changelog_uri: https://github.com/metanorma/postsvg
279
+ homepage_uri: https://github.com/claricle/postsvg
280
+ source_code_uri: https://github.com/claricle/postsvg
281
+ changelog_uri: https://github.com/claricle/postsvg/blob/main/CHANGELOG.md
282
+ bug_tracker_uri: https://github.com/claricle/postsvg/issues
98
283
  rubygems_mfa_required: 'true'
99
284
  post_install_message:
100
285
  rdoc_options: []
@@ -114,5 +299,5 @@ requirements: []
114
299
  rubygems_version: 3.5.22
115
300
  signing_key:
116
301
  specification_version: 4
117
- summary: Pure Ruby PostScript/EPS to SVG converter
302
+ summary: Pure Ruby bidirectional PS/EPS <-> SVG converter
118
303
  test_files: []
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Postsvg
4
- # Matrix transformation class for PostScript coordinate transformations
5
- # Implements affine transformation matrix [a b c d e f]
6
- class Matrix
7
- attr_accessor :a, :b, :c, :d, :e, :f
8
-
9
- def initialize(a: 1, b: 0, c: 0, d: 1, e: 0, f: 0)
10
- @a = a
11
- @b = b
12
- @c = c
13
- @d = d
14
- @e = e
15
- @f = f
16
- end
17
-
18
- def multiply(matrix)
19
- result = Matrix.new
20
- result.a = (@a * matrix.a) + (@c * matrix.b)
21
- result.b = (@b * matrix.a) + (@d * matrix.b)
22
- result.c = (@a * matrix.c) + (@c * matrix.d)
23
- result.d = (@b * matrix.c) + (@d * matrix.d)
24
- result.e = (@a * matrix.e) + (@c * matrix.f) + @e
25
- result.f = (@b * matrix.e) + (@d * matrix.f) + @f
26
- result
27
- end
28
-
29
- def translate(tx, ty)
30
- multiply(Matrix.new(e: tx, f: ty))
31
- end
32
-
33
- def scale(sx, sy)
34
- multiply(Matrix.new(a: sx, d: sy))
35
- end
36
-
37
- def rotate(degrees)
38
- radians = degrees * Math::PI / 180.0
39
- m = Matrix.new
40
- m.a = Math.cos(radians)
41
- m.b = Math.sin(radians)
42
- m.c = -Math.sin(radians)
43
- m.d = Math.cos(radians)
44
- multiply(m)
45
- end
46
-
47
- def skew_x(angle)
48
- radians = angle * Math::PI / 180.0
49
- multiply(Matrix.new(c: Math.tan(radians)))
50
- end
51
-
52
- def skew_y(angle)
53
- radians = angle * Math::PI / 180.0
54
- multiply(Matrix.new(b: Math.tan(radians)))
55
- end
56
-
57
- def to_transform_string
58
- "matrix(#{@a} #{@b} #{@c} #{@d} #{@e} #{@f})"
59
- end
60
-
61
- def apply_point(x, y)
62
- {
63
- x: (x * @a) + (y * @c) + @e,
64
- y: (x * @b) + (y * @d) + @f,
65
- }
66
- end
67
-
68
- def decompose
69
- scale_x = Math.hypot(@a, @b)
70
- scale_y = ((@a * @d) - (@b * @c)) / scale_x
71
-
72
- rotation = Math.atan2(@b, @a) * (180.0 / Math::PI)
73
-
74
- skew_x = Math.atan2((@a * @c) + (@b * @d), scale_x * scale_x)
75
- skew_y = Math.atan2((@a * @b) + (@c * @d), scale_y * scale_y)
76
-
77
- {
78
- translate: { x: @e, y: @f },
79
- scale: { x: scale_x, y: scale_y },
80
- rotate: rotation,
81
- skew: {
82
- x: skew_x * (180.0 / Math::PI),
83
- y: skew_y * (180.0 / Math::PI),
84
- },
85
- }
86
- end
87
-
88
- def invert
89
- det = (@a * @d) - (@b * @c)
90
- return Matrix.new if det.abs < 1e-10
91
-
92
- inv = Matrix.new
93
- inv.a = @d / det
94
- inv.b = -@b / det
95
- inv.c = -@c / det
96
- inv.d = @a / det
97
- inv.e = ((@c * @f) - (@d * @e)) / det
98
- inv.f = ((@b * @e) - (@a * @f)) / det
99
- inv
100
- end
101
-
102
- def identity?
103
- @a == 1 && @b.zero? && @c.zero? && @d == 1 && @e.zero? && @f.zero?
104
- end
105
- end
106
- end
data/postsvg.gemspec DELETED
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/postsvg/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "postsvg"
7
- spec.version = Postsvg::VERSION
8
- spec.authors = ["Ribose Inc."]
9
- spec.email = ["open.source@ribose.com"]
10
-
11
- spec.summary = "Pure Ruby PostScript/EPS to SVG converter"
12
- spec.description = <<~HEREDOC
13
- Postsvg provides a pure Ruby library for converting PostScript (PS) and
14
- Encapsulated PostScript (EPS) files to clean,
15
- standards-compliant Scalable Vector Graphics (SVG) format output.
16
- HEREDOC
17
-
18
- spec.homepage = "https://github.com/metanorma/postsvg"
19
- spec.license = "BSD-2-Clause"
20
- spec.required_ruby_version = ">= 3.0.0"
21
-
22
- spec.metadata["homepage_uri"] = spec.homepage
23
- spec.metadata["source_code_uri"] = "https://github.com/metanorma/postsvg"
24
- spec.metadata["changelog_uri"] = "https://github.com/metanorma/postsvg"
25
- spec.metadata["rubygems_mfa_required"] = "true"
26
-
27
- spec.files = Dir.chdir(__dir__) do
28
- `git ls-files -z`.split("\x0").reject do |f|
29
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
30
- end
31
- end
32
- spec.bindir = "exe"
33
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
34
- spec.require_paths = ["lib"]
35
-
36
- spec.add_dependency "parslet"
37
- spec.add_dependency "thor"
38
- end