svg_conform 0.1.11 → 0.2.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +1 -0
  3. data/.rubocop_todo.yml +74 -41
  4. data/CLAUDE.md +115 -0
  5. data/Gemfile +2 -0
  6. data/README.adoc +164 -0
  7. data/config/profiles/metanorma.yml +7 -0
  8. data/config/quality_metrics.yml +212 -0
  9. data/docs/image_quality.adoc +526 -0
  10. data/docs/performance.adoc +31 -0
  11. data/docs/profiles.adoc +3 -1
  12. data/docs/requirements.adoc +123 -0
  13. data/lib/svg_conform/cli.rb +19 -7
  14. data/lib/svg_conform/commands/check.rb +41 -45
  15. data/lib/svg_conform/commands/profiles.rb +3 -3
  16. data/lib/svg_conform/commands/quality.rb +249 -0
  17. data/lib/svg_conform/commands/svgcheck_compare.rb +29 -37
  18. data/lib/svg_conform/commands/svgcheck_compatibility.rb +11 -6
  19. data/lib/svg_conform/compatibility/report_formatter.rb +3 -5
  20. data/lib/svg_conform/compatibility_analyzer.rb +3 -3
  21. data/lib/svg_conform/document_analyzer.rb +9 -4
  22. data/lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb +5 -5
  23. data/lib/svg_conform/image_quality_analyzer.rb +225 -0
  24. data/lib/svg_conform/quality_metrics/complexity_calculator.rb +98 -0
  25. data/lib/svg_conform/quality_metrics/complexity_metrics.rb +56 -0
  26. data/lib/svg_conform/quality_metrics/configuration.rb +342 -0
  27. data/lib/svg_conform/quality_metrics/error_analyzer.rb +90 -0
  28. data/lib/svg_conform/quality_metrics/error_breakdown.rb +80 -0
  29. data/lib/svg_conform/quality_metrics/feature_detector.rb +55 -0
  30. data/lib/svg_conform/quality_metrics/feature_flags.rb +65 -0
  31. data/lib/svg_conform/quality_metrics/quality_calculator.rb +130 -0
  32. data/lib/svg_conform/quality_metrics/quality_report_formatter.rb +70 -0
  33. data/lib/svg_conform/quality_metrics/quality_result.rb +101 -0
  34. data/lib/svg_conform/quality_metrics/quality_score.rb +76 -0
  35. data/lib/svg_conform/quality_report.rb +342 -0
  36. data/lib/svg_conform/remediations/color_remediation.rb +1 -3
  37. data/lib/svg_conform/remediations/viewbox_remediation.rb +5 -9
  38. data/lib/svg_conform/requirements/base_requirement.rb +3 -3
  39. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +1 -1
  40. data/lib/svg_conform/requirements/style_requirement.rb +3 -2
  41. data/lib/svg_conform/requirements/text_as_path_requirement.rb +98 -0
  42. data/lib/svg_conform/requirements.rb +2 -0
  43. data/lib/svg_conform/sax_validation_handler.rb +3 -3
  44. data/lib/svg_conform/semantic_comparator.rb +3 -3
  45. data/lib/svg_conform/validation_result.rb +1 -1
  46. data/lib/svg_conform/version.rb +1 -1
  47. data/lib/svg_conform.rb +23 -0
  48. data/lib/tasks/fixtures.rake +1 -1
  49. data/spec/svg_conform/commands/check_command_spec.rb +2 -2
  50. data/spec/svg_conform/profiles/lucid_profile_spec.rb +0 -2
  51. data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +9 -9
  52. data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +0 -1
  53. data/spec/svg_conform/requirements/color_restrictions_requirement_spec.rb +0 -1
  54. data/spec/svg_conform/requirements/font_family_requirement_spec.rb +0 -1
  55. data/spec/svg_conform/requirements/forbidden_content_requirement_spec.rb +0 -1
  56. data/spec/svg_conform/requirements/id_reference_requirement_spec.rb +0 -1
  57. data/spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb +0 -1
  58. data/spec/svg_conform/requirements/link_validation_requirement_spec.rb +0 -1
  59. data/spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb +0 -1
  60. data/spec/svg_conform/requirements/namespace_requirement_spec.rb +0 -1
  61. data/spec/svg_conform/requirements/no_external_css_requirement_spec.rb +0 -1
  62. data/spec/svg_conform/requirements/style_promotion_requirement_spec.rb +0 -1
  63. data/spec/svg_conform/requirements/style_requirement_spec.rb +0 -1
  64. data/spec/svg_conform/requirements/text_as_path_requirement_spec.rb +142 -0
  65. data/spec/svg_conform/requirements/viewbox_required_requirement_spec.rb +0 -1
  66. data/spec/svg_conform_spec.rb +2 -2
  67. data/spec/svgcheck_compatibility_spec.rb +5 -13
  68. data/svg_conform.gemspec +3 -1
  69. metadata +38 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9300ab0026e52b929e0707e14c19ce45394da831dfd5e44f4afad14e1a2237cd
4
- data.tar.gz: b19b0d2dbce1397abb478105704c994a32f418972240c9c149d375d8be519e2c
3
+ metadata.gz: 2dd3f8b58d869e1375f4ec0e5c0c212d36dc5ae64ab91873ccc896acb9bd42b7
4
+ data.tar.gz: 184b07a501eb1bae6fc1691849df9f2fbb0693c340149822b35a0129b47ae2c0
5
5
  SHA512:
6
- metadata.gz: d413baac7ebb781837ff482103d751ce3222c170c613707b8411d5c6614dff71ac874802e0e5df14e276c0d56f537d32259787559359dfb954f6e3392088102d
7
- data.tar.gz: ca1a62500f77534fca87d5b0e0136328ed81b9d9a7a81510e312a3760f31157e7a42af4934bacda3af2d6915b675bb9f4afdba2746332922cb23351bcc47fba2
6
+ metadata.gz: 9db79546df082674dbfbe29bd010e7a676765bd08366e26af6da279d9b56d01a907e259178ef1b3009340aa22eb785098790b49aa1cb81525831d9b60ac8e962
7
+ data.tar.gz: '091d729bffcc2716bcce077e5509afbce8971329c1479e86bc8c2968ac540742c161f3a3f369c78fa0f76bdf6f5de84439b6c773349656f1466da4d3175e5ca5'
@@ -5,6 +5,7 @@ name: release
5
5
  permissions:
6
6
  contents: write
7
7
  packages: write
8
+ id-token: write
8
9
 
9
10
  on:
10
11
  workflow_dispatch:
data/.rubocop_todo.yml CHANGED
@@ -1,19 +1,11 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-01-27 00:27:35 UTC using RuboCop version 1.82.1.
3
+ # on 2026-04-09 13:07:51 UTC using RuboCop version 1.86.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 1
10
- # This cop supports safe autocorrection (--autocorrect).
11
- # Configuration parameters: EnforcedStyle, IndentationWidth.
12
- # SupportedStyles: with_first_argument, with_fixed_indentation
13
- Layout/ArgumentAlignment:
14
- Exclude:
15
- - 'lib/svg_conform/requirements/invalid_id_references_requirement.rb'
16
-
17
9
  # Offense count: 1
18
10
  # This cop supports safe autocorrection (--autocorrect).
19
11
  # Configuration parameters: EnforcedStyleAlignWith.
@@ -22,30 +14,19 @@ Layout/BlockAlignment:
22
14
  Exclude:
23
15
  - 'spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb'
24
16
 
25
- # Offense count: 1
26
- # This cop supports safe autocorrection (--autocorrect).
27
- # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
28
- # SupportedHashRocketStyles: key, separator, table
29
- # SupportedColonStyles: key, separator, table
30
- # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
31
- Layout/HashAlignment:
32
- Exclude:
33
- - 'spec/svg_conform/validation_context_spec.rb'
34
-
35
- # Offense count: 662
17
+ # Offense count: 667
36
18
  # This cop supports safe autocorrection (--autocorrect).
37
19
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
38
20
  # URISchemes: http, https
39
21
  Layout/LineLength:
40
22
  Enabled: false
41
23
 
42
- # Offense count: 2
24
+ # Offense count: 9
43
25
  # This cop supports safe autocorrection (--autocorrect).
44
26
  # Configuration parameters: AllowInHeredoc.
45
27
  Layout/TrailingWhitespace:
46
28
  Exclude:
47
- - 'lib/svg_conform/requirements/invalid_id_references_requirement.rb'
48
- - 'spec/svg_conform/validation_context_spec.rb'
29
+ - 'spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb'
49
30
 
50
31
  # Offense count: 3
51
32
  # Configuration parameters: AllowedMethods.
@@ -73,12 +54,20 @@ Lint/DuplicateCaseCondition:
73
54
  Exclude:
74
55
  - 'lib/svg_conform/semantic_comparator.rb'
75
56
 
76
- # Offense count: 1
57
+ # Offense count: 2
77
58
  Lint/DuplicateMethods:
78
59
  Exclude:
79
60
  - 'lib/svg_conform/sax_validation_handler.rb'
61
+ - 'spec/svg_conform/validation_context_spec.rb'
80
62
 
81
- # Offense count: 2
63
+ # Offense count: 1
64
+ # This cop supports safe autocorrection (--autocorrect).
65
+ # Configuration parameters: AllowComments.
66
+ Lint/EmptyConditionalBody:
67
+ Exclude:
68
+ - 'spec/svgcheck_compatibility_spec.rb'
69
+
70
+ # Offense count: 1
82
71
  Lint/HashCompareByIdentity:
83
72
  Exclude:
84
73
  - 'lib/svg_conform/document_analyzer.rb'
@@ -91,17 +80,12 @@ Lint/MissingSuper:
91
80
  - 'lib/svg_conform/compatibility/validity_analysis.rb'
92
81
  - 'lib/svg_conform/sax_validation_handler.rb'
93
82
 
94
- # Offense count: 1
95
- Lint/UnreachableCode:
96
- Exclude:
97
- - 'lib/svg_conform/commands/check.rb'
98
-
99
- # Offense count: 146
83
+ # Offense count: 160
100
84
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
101
85
  Metrics/AbcSize:
102
86
  Enabled: false
103
87
 
104
- # Offense count: 24
88
+ # Offense count: 25
105
89
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
106
90
  # AllowedMethods: refine
107
91
  Metrics/BlockLength:
@@ -112,26 +96,38 @@ Metrics/BlockLength:
112
96
  Metrics/BlockNesting:
113
97
  Max: 4
114
98
 
115
- # Offense count: 125
99
+ # Offense count: 138
116
100
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
117
101
  Metrics/CyclomaticComplexity:
118
102
  Enabled: false
119
103
 
120
- # Offense count: 259
104
+ # Offense count: 276
121
105
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
122
106
  Metrics/MethodLength:
123
107
  Max: 154
124
108
 
125
- # Offense count: 6
109
+ # Offense count: 8
126
110
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
127
111
  Metrics/ParameterLists:
128
112
  Max: 9
129
113
 
130
- # Offense count: 99
114
+ # Offense count: 112
131
115
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
132
116
  Metrics/PerceivedComplexity:
133
117
  Enabled: false
134
118
 
119
+ # Offense count: 9
120
+ # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
121
+ # AllowedMethods: call
122
+ # WaywardPredicates: infinite?, nonzero?
123
+ Naming/PredicateMethod:
124
+ Exclude:
125
+ - 'lib/svg_conform/compatibility/file_processor.rb'
126
+ - 'lib/svg_conform/node_helpers.rb'
127
+ - 'lib/svg_conform/remediations/base_remediation.rb'
128
+ - 'lib/svg_conform/requirements/style_requirement.rb'
129
+ - 'lib/svg_conform/semantic_comparator.rb'
130
+
135
131
  # Offense count: 2
136
132
  # Configuration parameters: MinSize.
137
133
  Performance/CollectionLiteralInLoop:
@@ -161,13 +157,18 @@ RSpec/DescribeClass:
161
157
  # Offense count: 157
162
158
  # Configuration parameters: CountAsOne.
163
159
  RSpec/ExampleLength:
164
- Max: 53
160
+ Max: 43
165
161
 
166
162
  # Offense count: 3
167
163
  RSpec/LeakyConstantDeclaration:
168
164
  Exclude:
169
165
  - 'spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb'
170
166
 
167
+ # Offense count: 1
168
+ RSpec/LeakyLocalVariable:
169
+ Exclude:
170
+ - 'spec/svgcheck_compatibility_spec.rb'
171
+
171
172
  # Offense count: 2
172
173
  # Configuration parameters: .
173
174
  # SupportedStyles: have_received, receive
@@ -183,11 +184,31 @@ RSpec/MultipleDescribes:
183
184
  RSpec/MultipleExpectations:
184
185
  Max: 8
185
186
 
187
+ # Offense count: 11
188
+ # This cop supports unsafe autocorrection (--autocorrect-all).
189
+ RSpec/Output:
190
+ Exclude:
191
+ - 'spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb'
192
+ - 'spec/svg_conform/remediations/color_remediation_spec.rb'
193
+ - 'spec/svg_conform/remediations/font_remediation_spec.rb'
194
+ - 'spec/svg_conform/remediations/invalid_id_references_remediation_spec.rb'
195
+ - 'spec/svg_conform/remediations/namespace_attribute_remediation_spec.rb'
196
+ - 'spec/svg_conform/remediations/namespace_remediation_spec.rb'
197
+ - 'spec/svg_conform/remediations/no_external_css_remediation_spec.rb'
198
+ - 'spec/svg_conform/remediations/style_promotion_remediation_spec.rb'
199
+ - 'spec/svg_conform/remediations/viewbox_remediation_spec.rb'
200
+
186
201
  # Offense count: 1
187
202
  Rake/MethodDefinitionInTask:
188
203
  Exclude:
189
204
  - 'lib/tasks/svgcheck.rake'
190
205
 
206
+ # Offense count: 3
207
+ # This cop supports safe autocorrection (--autocorrect).
208
+ Style/ComparableClamp:
209
+ Exclude:
210
+ - 'lib/svg_conform/css_color.rb'
211
+
191
212
  # Offense count: 2
192
213
  # This cop supports safe autocorrection (--autocorrect).
193
214
  # Configuration parameters: EnforcedStyle, AllowComments.
@@ -197,17 +218,29 @@ Style/EmptyElse:
197
218
  - 'lib/svg_conform/remediations/namespace_remediation.rb'
198
219
  - 'lib/svg_conform/requirements/style_requirement.rb'
199
220
 
200
- # Offense count: 23
221
+ # Offense count: 13
201
222
  # This cop supports safe autocorrection (--autocorrect).
202
223
  # Configuration parameters: MaxUnannotatedPlaceholdersAllowed, Mode, AllowedMethods, AllowedPatterns.
203
224
  # SupportedStyles: annotated, template, unannotated
204
225
  Style/FormatStringToken:
205
226
  EnforcedStyle: unannotated
206
227
 
228
+ # Offense count: 2
229
+ # This cop supports unsafe autocorrection (--autocorrect-all).
230
+ Style/HashSlice:
231
+ Exclude:
232
+ - 'spec/svg_conform_spec.rb'
233
+
234
+ # Offense count: 1
235
+ # Configuration parameters: AllowedClasses.
236
+ Style/OneClassPerFile:
237
+ Exclude:
238
+ - 'lib/svg_conform/compatibility/report_formatter.rb'
239
+
207
240
  # Offense count: 1
208
- Style/MissingRespondToMissing:
241
+ Style/OpenStructUse:
209
242
  Exclude:
210
- - 'lib/svg_conform/cli.rb'
243
+ - 'lib/svg_conform/validator.rb'
211
244
 
212
245
  # Offense count: 4
213
246
  # Configuration parameters: AllowedMethods.
@@ -219,7 +252,7 @@ Style/OptionalBooleanParameter:
219
252
  # Offense count: 1
220
253
  # This cop supports safe autocorrection (--autocorrect).
221
254
  # Configuration parameters: AllowedMethods.
222
- # AllowedMethods: nonzero?
255
+ # AllowedMethods: infinite?, nonzero?
223
256
  Style/RedundantCondition:
224
257
  Exclude:
225
258
  - 'lib/svg_conform/external_checkers/svgcheck/parser.rb'
data/CLAUDE.md ADDED
@@ -0,0 +1,115 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Build/Test Commands
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ bin/setup
10
+
11
+ # Run tests
12
+ rake spec
13
+
14
+ # Run a single spec file
15
+ bundle exec rspec spec/svg_conform/validator_spec.rb
16
+
17
+ # Run tests with detailed output
18
+ bundle exec rspec --format documentation
19
+
20
+ # Run linting
21
+ rake rubocop
22
+
23
+ # Run both tests and linting
24
+ rake
25
+
26
+ # Run a specific test by line number
27
+ bundle exec rspec spec/svg_conform/validator_spec.rb:42
28
+ ```
29
+
30
+ ## Architecture
31
+
32
+ ### Two-Mode Validation System
33
+
34
+ SvgConform uses two distinct operating modes:
35
+
36
+ 1. **SAX Validation Mode** (always used for validation):
37
+ - Memory-safe streaming XML parser
38
+ - Constant memory regardless of file size
39
+ - Handles files of any size (tested with 100MB+)
40
+ - Read-only, cannot modify documents
41
+ - Implemented via `SaxDocument` and `SaxValidationHandler`
42
+
43
+ 2. **DOM Remediation Mode** (only when applying fixes):
44
+ - Full document tree loaded in memory
45
+ - XPath queries and tree modification
46
+ - Memory scales with file size
47
+ - Only activated when `fix: true` is specified
48
+
49
+ ### Core Classes
50
+
51
+ - `Validator` - Main entry point; normalizes all inputs to SAX validation
52
+ - `SaxDocument` - SAX-based document wrapper for memory-safe validation
53
+ - `Document` - DOM-based document wrapper for modifications
54
+ - `Profile` - Collection of requirements and remediations; loaded from YAML
55
+ - `Profiles` - Factory for loading/retrieving profile instances
56
+ - `ValidationContext` - Carries state during validation (errors, data collected)
57
+ - `ValidationResult` - Holds validation outcomes after checking
58
+ - `ConformanceReport` - Formats validation results for output
59
+
60
+ ### Requirements System
61
+
62
+ Requirements validate SVG documents. All requirements must support SAX validation:
63
+
64
+ - Requirements inherit from `BaseRequirement` in `lib/svg_conform/requirements/`
65
+ - Must implement `validate_sax_element(element, context)` for immediate checks
66
+ - Can optionally implement `collect_sax_data()` + `validate_sax_complete()` for deferred validation (e.g., cross-reference checks)
67
+ - Use `context.data` hash for per-document state (not instance variables - they leak across validations)
68
+ - Never attempt DOM operations in SAX callbacks
69
+
70
+ Key requirement classes: `NamespaceRequirement`, `ViewboxRequiredRequirement`, `IdReferenceRequirement`, `ForbiddenContentRequirement`, `ColorRestrictionsRequirement`, etc.
71
+
72
+ ### Remediations System
73
+
74
+ Remediations fix validation failures. They run in DOM mode:
75
+
76
+ - Inherit from `BaseRemediation` in `lib/svg_conform/remediations/`
77
+ - Linked to requirements via `targets` array in profile YAML
78
+ - Only execute when `should_execute?(failed_requirements)` returns true
79
+
80
+ ### Profile Configuration
81
+
82
+ Profiles are defined in YAML under `config/profiles/`:
83
+ - `base.yml` - Common requirements shared by other profiles
84
+ - `metanorma.yml`, `svg_1_2_rfc.yml`, etc. - Specific profile definitions
85
+ - Profile class map is built dynamically from filesystem in `Profile.build_class_map`
86
+
87
+ Profiles support `import` to inherit from other profiles (e.g., `metanorma` imports `base`).
88
+
89
+ ### CLI Structure
90
+
91
+ - `lib/svg_conform/cli.rb` - Thor-based CLI entry point
92
+ - `lib/svg_conform/commands/check.rb` - Main validation command
93
+ - `lib/svg_conform/commands/profiles.rb` - Profile listing command
94
+ - `lib/svg_conform/commands/svgcheck.rb` - SVGCheck compatibility subcommands
95
+
96
+ ### Input Handling
97
+
98
+ The `Validator` accepts multiple input types and always uses SAX:
99
+ - String (XML content) → parsed directly with SAX
100
+ - Moxml/Nokogiri documents → serialized once, then SAX validated
101
+ - Document/Element objects → same serialization approach
102
+
103
+ This ensures memory safety for large files regardless of input type.
104
+
105
+ ### Key Files
106
+
107
+ - `lib/svg_conform.rb` - Main require file with autoloads
108
+ - `lib/svg_conform/element_proxy.rb` - Lightweight SAX element representation
109
+ - `lib/svg_conform/validation_context.rb` - Validation state container
110
+ - `lib/svg_conform/sax_document.rb` - SAX document wrapper
111
+ - `lib/svg_conform/sax_validation_handler.rb` - SAX callback handler
112
+
113
+ ### Error Handling Pattern
114
+
115
+ The CLI uses `exit 1` for error exits. When improving error handling, prefer raising proper Ruby exceptions (`ValidationError`, `ProfileError`, `ArgumentError`) rather than using `exit`/`abort` directly, as Thor provides mechanisms for displaying errors gracefully to users.
data/Gemfile CHANGED
@@ -6,6 +6,8 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "canon", "~>0.1.10"
9
+ gem "lutaml-model", github: "lutaml/lutaml-model", branch: "main"
10
+ gem "moxml", github: "lutaml/moxml", branch: "main"
9
11
  gem "openssl", "~> 3.0"
10
12
  gem "rake"
11
13
  gem "rspec"
data/README.adoc CHANGED
@@ -33,6 +33,7 @@ SvgConform is distributed as a Ruby gem.
33
33
  * **100% SVGCheck compatibility**: Perfect error report matching with Python svgcheck tool
34
34
  * **Configurable RDF metadata support**: Choose strict or permissive RDF/Dublin Core handling
35
35
  * **Generic namespace handling**: Configuration-driven foreign namespace validation
36
+ * **Text-as-path detection**: Warns when text is rendered as outlined path glyphs (quality check)
36
37
 
37
38
 
38
39
  == Concepts
@@ -360,6 +361,168 @@ SvgConform provides compatibility with existing SVG validation tools:
360
361
  See link:docs/compatibility.adoc[Compatibility Documentation] for details.
361
362
 
362
363
 
364
+ [[image_quality]]
365
+ == Image quality metric
366
+
367
+ SvgConform provides a quality metric system for analyzing and scoring SVG files
368
+ across multiple dimensions:
369
+
370
+ * **Quality Score (0-100)**: Composite score based on error density, severity, and remediability
371
+ * **Quality Level**: EXCELLENT, GOOD, FAIR, POOR, or CRITICAL
372
+ * **Error Breakdown**: Counts by severity (critical, high, medium, low) and remediability
373
+ * **Complexity Index**: 1-10 scale based on element count and advanced features
374
+ * **Feature Detection**: Base64 images, foreign namespaces, masks, clip paths, external refs
375
+
376
+ Reports are fully object-oriented: the same report object supports `to_yaml`, `to_json`,
377
+ and colorful terminal rendering.
378
+
379
+ [IMPORTANT]
380
+ .Quality depends on validation profile
381
+ ====
382
+ The quality score is calculated based on validation errors, which depend on the
383
+ chosen profile. Different profiles have different rules, so the same SVG file
384
+ may receive different quality scores under different profiles.
385
+
386
+ Example: `colors.svg` scores 60 (FAIR) under `svg_1_2_rfc` but 100 (EXCELLENT)
387
+ under `metanorma` because the profiles have different color restrictions.
388
+ ====
389
+
390
+ [source,bash]
391
+ ----
392
+ # Integrated into main CLI (svg_conform quality analyze)
393
+ svg_conform quality analyze image.svg
394
+
395
+ # Output as YAML
396
+ svg_conform quality analyze image.svg -- --format yaml
397
+
398
+ # Batch analyze a directory
399
+ svg_conform quality batch ./svgs -- --output quality_report.csv
400
+
401
+ # With different profile (affects quality score!)
402
+ svg_conform quality analyze image.svg -- --profile metanorma
403
+ ----
404
+
405
+ [source,ruby]
406
+ ----
407
+ # Single file analysis - returns SvgQualityReport object
408
+ analyzer = SvgConform::ImageQualityAnalyzer.new
409
+ report = analyzer.analyze('image.svg')
410
+
411
+ # Three output formats from the same object
412
+ puts report.render # Colorful terminal output
413
+ puts report.to_yaml # YAML serialization
414
+ puts report.to_json # JSON serialization
415
+
416
+ # Access attributes directly
417
+ puts "Quality: #{report.quality_score} (#{report.quality_level})"
418
+ puts "Errors: #{report.error_count} (#{report.remediable_errors} remediable)"
419
+ puts "Complexity: #{report.complexity_index}/10"
420
+
421
+ # Batch analysis - returns SvgQualityBatchReport object
422
+ batch = analyzer.analyze_batch('./svgs')
423
+ puts batch.render # Summary with distribution chart
424
+ puts batch.to_yaml # Full YAML with all reports
425
+
426
+ # Filter and process reports
427
+ poor_files = batch.reports.select { |r| r.quality_level == :poor }
428
+ ----
429
+
430
+ For detailed documentation including custom configuration and CLI options, see
431
+ link:docs/image_quality.adoc[Image Quality Metric Documentation].
432
+
433
+ === CLI output examples
434
+
435
+ .Single file analysis with default profile (svg_1_2_rfc)
436
+ [source,text]
437
+ ----
438
+ $ svg_conform quality analyze spec/fixtures/svgcheck/inputs/colors.svg
439
+
440
+ 📊 SVG Quality Report: colors.svg
441
+
442
+ ⚠️ Quality: 60 (FAIR)
443
+ 🔶 Content Health: moderate_issues
444
+
445
+ 📁 File: 1.41 KB (small)
446
+ 📐 Elements: 17
447
+ 🔢 Complexity: 1.0/10
448
+
449
+ Errors: 12
450
+ 🔧 Remediable: 12
451
+ ⚠️ Non-remediable: 0
452
+
453
+ Breakdown:
454
+ ● Medium: 12
455
+ ----
456
+
457
+ .Same file with metanorma profile (no color restrictions)
458
+ [source,text]
459
+ ----
460
+ $ svg_conform quality analyze spec/fixtures/svgcheck/inputs/colors.svg -- --profile metanorma
461
+
462
+ 📊 SVG Quality Report: colors.svg
463
+
464
+ ✨ Quality: 100 (EXCELLENT)
465
+ ✅ Content Health: good
466
+
467
+ 📁 File: 1.41 KB (small)
468
+ 📐 Elements: 17
469
+ 🔢 Complexity: 1.0/10
470
+
471
+ Errors: 0
472
+ 🔧 Remediable: 0
473
+ ⚠️ Non-remediable: 0
474
+ ----
475
+
476
+ .Single file analysis (YAML output)
477
+ [source,yaml]
478
+ ----
479
+ $ svg_conform quality analyze spec/fixtures/svgcheck/inputs/colors.svg -- --format yaml
480
+
481
+ ---
482
+ file_path: spec/fixtures/svgcheck/inputs/colors.svg
483
+ quality_score: 60
484
+ quality_level: :fair
485
+ error_count: 12
486
+ remediable_errors: 12
487
+ ...
488
+ ----
489
+
490
+ .Single file analysis (JSON output)
491
+ [source,json]
492
+ ----
493
+ $ svg_conform quality analyze spec/fixtures/svgcheck/inputs/colors.svg -- --format json
494
+
495
+ {"file_path":"spec/fixtures/svgcheck/inputs/colors.svg","quality_score":60,...}
496
+ ----
497
+
498
+ .Batch summary (terminal output with distribution chart)
499
+ [source,text]
500
+ ----
501
+ $ svg_conform quality batch spec/fixtures/svgcheck/inputs -- --summary-only
502
+
503
+ 📊 SVG Quality Batch Report
504
+
505
+ 📁 Total Files: 19
506
+ ✅ Successful: 19
507
+
508
+ Quality Distribution
509
+
510
+ ✨ EXCELLENT ██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2 (10.5%)
511
+ 👍 GOOD ██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2 (10.5%)
512
+ ⚠️ FAIR ████████████████████████████████████████ 13 (68.4%)
513
+ 😟 POOR ██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2 (10.5%)
514
+ 💥 CRITICAL ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0 (0.0%)
515
+
516
+ Summary
517
+
518
+ 📈 Average Quality Score: 61.6/100
519
+ 📊 Average Errors/File: 204.3
520
+
521
+ 🔧 Total Remediable: 3872
522
+ ⚠️ Total Non-remediable: 10
523
+ ----
524
+
525
+
363
526
  == Documentation
364
527
 
365
528
  === User documentation
@@ -371,6 +534,7 @@ See link:docs/compatibility.adoc[Compatibility Documentation] for details.
371
534
  * link:docs/remediation.adoc[Remediation Reference] - All automatic remediations
372
535
  * link:docs/reference_manifest.adoc[Reference Manifest] - ID and reference tracking
373
536
  * link:docs/rdf_metadata_support.adoc[RDF Metadata Support] - RDF/Dublin Core configuration
537
+ * link:docs/image_quality.adoc[Image Quality Metric] - Quality scoring and analysis
374
538
 
375
539
  === Developer documentation
376
540
 
@@ -187,6 +187,13 @@ requirements:
187
187
  check_image_elements: true
188
188
  check_style_images: true
189
189
 
190
+ # Text-as-path detection - warns when text is rendered as outlined paths
191
+ - id: "text_as_path"
192
+ type: "TextAsPathRequirement"
193
+ description: "Detects text rendered as outlined paths instead of native <text> elements"
194
+ min_d_length: 500
195
+ min_bezier: 5
196
+
190
197
  remediations:
191
198
  # ViewBox auto-generation
192
199
  - id: "viewbox_generation"