svg_conform 0.1.12 → 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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +33 -109
  3. data/Gemfile +2 -0
  4. data/README.adoc +164 -0
  5. data/config/profiles/metanorma.yml +7 -0
  6. data/config/quality_metrics.yml +212 -0
  7. data/docs/image_quality.adoc +526 -0
  8. data/docs/performance.adoc +31 -0
  9. data/docs/profiles.adoc +3 -1
  10. data/docs/requirements.adoc +123 -0
  11. data/lib/svg_conform/cli.rb +5 -0
  12. data/lib/svg_conform/commands/quality.rb +249 -0
  13. data/lib/svg_conform/compatibility/report_formatter.rb +3 -5
  14. data/lib/svg_conform/compatibility_analyzer.rb +3 -3
  15. data/lib/svg_conform/document_analyzer.rb +9 -4
  16. data/lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb +5 -5
  17. data/lib/svg_conform/image_quality_analyzer.rb +225 -0
  18. data/lib/svg_conform/quality_metrics/complexity_calculator.rb +98 -0
  19. data/lib/svg_conform/quality_metrics/complexity_metrics.rb +56 -0
  20. data/lib/svg_conform/quality_metrics/configuration.rb +342 -0
  21. data/lib/svg_conform/quality_metrics/error_analyzer.rb +90 -0
  22. data/lib/svg_conform/quality_metrics/error_breakdown.rb +80 -0
  23. data/lib/svg_conform/quality_metrics/feature_detector.rb +55 -0
  24. data/lib/svg_conform/quality_metrics/feature_flags.rb +65 -0
  25. data/lib/svg_conform/quality_metrics/quality_calculator.rb +130 -0
  26. data/lib/svg_conform/quality_metrics/quality_report_formatter.rb +70 -0
  27. data/lib/svg_conform/quality_metrics/quality_result.rb +101 -0
  28. data/lib/svg_conform/quality_metrics/quality_score.rb +76 -0
  29. data/lib/svg_conform/quality_report.rb +342 -0
  30. data/lib/svg_conform/remediations/color_remediation.rb +1 -3
  31. data/lib/svg_conform/remediations/viewbox_remediation.rb +5 -9
  32. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +1 -1
  33. data/lib/svg_conform/requirements/style_requirement.rb +3 -2
  34. data/lib/svg_conform/requirements/text_as_path_requirement.rb +98 -0
  35. data/lib/svg_conform/requirements.rb +2 -0
  36. data/lib/svg_conform/sax_validation_handler.rb +3 -3
  37. data/lib/svg_conform/semantic_comparator.rb +3 -3
  38. data/lib/svg_conform/validation_result.rb +1 -1
  39. data/lib/svg_conform/version.rb +1 -1
  40. data/lib/svg_conform.rb +23 -0
  41. data/lib/tasks/fixtures.rake +1 -1
  42. data/spec/svg_conform/profiles/lucid_profile_spec.rb +0 -2
  43. data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +9 -9
  44. data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +0 -1
  45. data/spec/svg_conform/requirements/color_restrictions_requirement_spec.rb +0 -1
  46. data/spec/svg_conform/requirements/font_family_requirement_spec.rb +0 -1
  47. data/spec/svg_conform/requirements/forbidden_content_requirement_spec.rb +0 -1
  48. data/spec/svg_conform/requirements/id_reference_requirement_spec.rb +0 -1
  49. data/spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb +0 -1
  50. data/spec/svg_conform/requirements/link_validation_requirement_spec.rb +0 -1
  51. data/spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb +0 -1
  52. data/spec/svg_conform/requirements/namespace_requirement_spec.rb +0 -1
  53. data/spec/svg_conform/requirements/no_external_css_requirement_spec.rb +0 -1
  54. data/spec/svg_conform/requirements/style_promotion_requirement_spec.rb +0 -1
  55. data/spec/svg_conform/requirements/style_requirement_spec.rb +0 -1
  56. data/spec/svg_conform/requirements/text_as_path_requirement_spec.rb +142 -0
  57. data/spec/svg_conform/requirements/viewbox_required_requirement_spec.rb +0 -1
  58. data/spec/svg_conform_spec.rb +2 -2
  59. data/spec/svgcheck_compatibility_spec.rb +5 -13
  60. data/svg_conform.gemspec +3 -1
  61. metadata +37 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 162ed406493cfabb9a3cb94a3a6ba2ee3ed4ae95d3edf912034c17974d5cc496
4
- data.tar.gz: 56cb8b2d5e94bcce3cc1e32b513a738ac2140f0e86848e6c101fc08ed16cfc7a
3
+ metadata.gz: 2dd3f8b58d869e1375f4ec0e5c0c212d36dc5ae64ab91873ccc896acb9bd42b7
4
+ data.tar.gz: 184b07a501eb1bae6fc1691849df9f2fbb0693c340149822b35a0129b47ae2c0
5
5
  SHA512:
6
- metadata.gz: 1bcbdf1a7dbc43f044aa875d7a310b85064bcd47d5f227cf962303d1f3a0d024fe926b87ffc201fbf5256b0e150cfa71b5a8702e84b062b37d7935a50bc96b5b
7
- data.tar.gz: 817c9ac5561b509c39e9f4d228b4165d3943a242bb83a88c77e8388bbce99c6746dc9c9df464a729ce44160c331b08ce9dfcc06e98c676c2944631eaf35346e5
6
+ metadata.gz: 9db79546df082674dbfbe29bd010e7a676765bd08366e26af6da279d9b56d01a907e259178ef1b3009340aa22eb785098790b49aa1cb81525831d9b60ac8e962
7
+ data.tar.gz: '091d729bffcc2716bcce077e5509afbce8971329c1479e86bc8c2968ac540742c161f3a3f369c78fa0f76bdf6f5de84439b6c773349656f1466da4d3175e5ca5'
data/.rubocop_todo.yml CHANGED
@@ -1,17 +1,11 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-04-04 08:57:24 UTC using RuboCop version 1.86.0.
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
- Gemspec/RequireMFA:
12
- Exclude:
13
- - 'svg_conform.gemspec'
14
-
15
9
  # Offense count: 1
16
10
  # This cop supports safe autocorrection (--autocorrect).
17
11
  # Configuration parameters: EnforcedStyleAlignWith.
@@ -20,44 +14,19 @@ Layout/BlockAlignment:
20
14
  Exclude:
21
15
  - 'spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb'
22
16
 
23
- # Offense count: 1
24
- # This cop supports safe autocorrection (--autocorrect).
25
- # Configuration parameters: EnforcedStyle.
26
- # SupportedStyles: leading, trailing
27
- Layout/LineContinuationLeadingSpace:
28
- Exclude:
29
- - 'spec/svgcheck_compatibility_spec.rb'
30
-
31
- # Offense count: 5
32
- # This cop supports safe autocorrection (--autocorrect).
33
- # Configuration parameters: EnforcedStyle, IndentationWidth.
34
- # SupportedStyles: aligned, indented
35
- Layout/LineEndStringConcatenationIndentation:
36
- Exclude:
37
- - 'lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb'
38
- - 'spec/svgcheck_compatibility_spec.rb'
39
-
40
- # Offense count: 649
17
+ # Offense count: 667
41
18
  # This cop supports safe autocorrection (--autocorrect).
42
19
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
43
20
  # URISchemes: http, https
44
21
  Layout/LineLength:
45
22
  Enabled: false
46
23
 
47
- # Offense count: 13
24
+ # Offense count: 9
48
25
  # This cop supports safe autocorrection (--autocorrect).
49
- Lint/AmbiguousOperatorPrecedence:
26
+ # Configuration parameters: AllowInHeredoc.
27
+ Layout/TrailingWhitespace:
50
28
  Exclude:
51
- - 'lib/svg_conform/compatibility_analyzer.rb'
52
- - 'lib/svg_conform/semantic_comparator.rb'
53
- - 'lib/svg_conform/validation_result.rb'
54
-
55
- # Offense count: 1
56
- # This cop supports unsafe autocorrection (--autocorrect-all).
57
- # Configuration parameters: RequireParenthesesForMethodChains.
58
- Lint/AmbiguousRange:
59
- Exclude:
60
- - 'lib/svg_conform/compatibility/report_formatter.rb'
29
+ - 'spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb'
61
30
 
62
31
  # Offense count: 3
63
32
  # Configuration parameters: AllowedMethods.
@@ -91,7 +60,14 @@ Lint/DuplicateMethods:
91
60
  - 'lib/svg_conform/sax_validation_handler.rb'
92
61
  - 'spec/svg_conform/validation_context_spec.rb'
93
62
 
94
- # 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
95
71
  Lint/HashCompareByIdentity:
96
72
  Exclude:
97
73
  - 'lib/svg_conform/document_analyzer.rb'
@@ -104,24 +80,12 @@ Lint/MissingSuper:
104
80
  - 'lib/svg_conform/compatibility/validity_analysis.rb'
105
81
  - 'lib/svg_conform/sax_validation_handler.rb'
106
82
 
107
- # Offense count: 1
108
- # This cop supports unsafe autocorrection (--autocorrect-all).
109
- Lint/RedundantDirGlobSort:
110
- Exclude:
111
- - 'lib/tasks/fixtures.rake'
112
-
113
- # Offense count: 1
114
- # This cop supports unsafe autocorrection (--autocorrect-all).
115
- Lint/SuppressedExceptionInNumberConversion:
116
- Exclude:
117
- - 'lib/svg_conform/remediations/viewbox_remediation.rb'
118
-
119
- # Offense count: 145
83
+ # Offense count: 160
120
84
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
121
85
  Metrics/AbcSize:
122
86
  Enabled: false
123
87
 
124
- # Offense count: 24
88
+ # Offense count: 25
125
89
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
126
90
  # AllowedMethods: refine
127
91
  Metrics/BlockLength:
@@ -132,22 +96,22 @@ Metrics/BlockLength:
132
96
  Metrics/BlockNesting:
133
97
  Max: 4
134
98
 
135
- # Offense count: 125
99
+ # Offense count: 138
136
100
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
137
101
  Metrics/CyclomaticComplexity:
138
102
  Enabled: false
139
103
 
140
- # Offense count: 256
104
+ # Offense count: 276
141
105
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
142
106
  Metrics/MethodLength:
143
107
  Max: 154
144
108
 
145
- # Offense count: 6
109
+ # Offense count: 8
146
110
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
147
111
  Metrics/ParameterLists:
148
112
  Max: 9
149
113
 
150
- # Offense count: 99
114
+ # Offense count: 112
151
115
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
152
116
  Metrics/PerceivedComplexity:
153
117
  Enabled: false
@@ -171,12 +135,6 @@ Performance/CollectionLiteralInLoop:
171
135
  - 'lib/svg_conform/batch_report.rb'
172
136
  - 'lib/svg_conform/compatibility/pattern_discovery.rb'
173
137
 
174
- # Offense count: 2
175
- # This cop supports unsafe autocorrection (--autocorrect-all).
176
- Performance/MapCompact:
177
- Exclude:
178
- - 'lib/svg_conform/remediations/viewbox_remediation.rb'
179
-
180
138
  # Offense count: 9
181
139
  # Configuration parameters: IgnoredMetadata.
182
140
  RSpec/DescribeClass:
@@ -199,7 +157,7 @@ RSpec/DescribeClass:
199
157
  # Offense count: 157
200
158
  # Configuration parameters: CountAsOne.
201
159
  RSpec/ExampleLength:
202
- Max: 53
160
+ Max: 43
203
161
 
204
162
  # Offense count: 3
205
163
  RSpec/LeakyConstantDeclaration:
@@ -226,10 +184,19 @@ RSpec/MultipleDescribes:
226
184
  RSpec/MultipleExpectations:
227
185
  Max: 8
228
186
 
229
- # Offense count: 44
187
+ # Offense count: 11
230
188
  # This cop supports unsafe autocorrection (--autocorrect-all).
231
189
  RSpec/Output:
232
- Enabled: false
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'
233
200
 
234
201
  # Offense count: 1
235
202
  Rake/MethodDefinitionInTask:
@@ -251,20 +218,13 @@ Style/EmptyElse:
251
218
  - 'lib/svg_conform/remediations/namespace_remediation.rb'
252
219
  - 'lib/svg_conform/requirements/style_requirement.rb'
253
220
 
254
- # Offense count: 23
221
+ # Offense count: 13
255
222
  # This cop supports safe autocorrection (--autocorrect).
256
223
  # Configuration parameters: MaxUnannotatedPlaceholdersAllowed, Mode, AllowedMethods, AllowedPatterns.
257
224
  # SupportedStyles: annotated, template, unannotated
258
225
  Style/FormatStringToken:
259
226
  EnforcedStyle: unannotated
260
227
 
261
- # Offense count: 1
262
- # This cop supports unsafe autocorrection (--autocorrect-all).
263
- # Configuration parameters: AllowSplatArgument.
264
- Style/HashConversion:
265
- Exclude:
266
- - 'lib/svg_conform/sax_validation_handler.rb'
267
-
268
228
  # Offense count: 2
269
229
  # This cop supports unsafe autocorrection (--autocorrect-all).
270
230
  Style/HashSlice:
@@ -289,18 +249,6 @@ Style/OptionalBooleanParameter:
289
249
  Exclude:
290
250
  - 'lib/svg_conform/semantic_comparator.rb'
291
251
 
292
- # Offense count: 1
293
- # This cop supports unsafe autocorrection (--autocorrect-all).
294
- Style/PartitionInsteadOfDoubleSelect:
295
- Exclude:
296
- - 'lib/svg_conform/requirements/style_requirement.rb'
297
-
298
- # Offense count: 1
299
- # This cop supports unsafe autocorrection (--autocorrect-all).
300
- Style/ReduceToHash:
301
- Exclude:
302
- - 'lib/svg_conform/requirements/base_requirement.rb'
303
-
304
252
  # Offense count: 1
305
253
  # This cop supports safe autocorrection (--autocorrect).
306
254
  # Configuration parameters: AllowedMethods.
@@ -308,27 +256,3 @@ Style/ReduceToHash:
308
256
  Style/RedundantCondition:
309
257
  Exclude:
310
258
  - 'lib/svg_conform/external_checkers/svgcheck/parser.rb'
311
-
312
- # Offense count: 2
313
- # This cop supports unsafe autocorrection (--autocorrect-all).
314
- Style/RedundantFormat:
315
- Exclude:
316
- - 'lib/svg_conform/compatibility/report_formatter.rb'
317
-
318
- # Offense count: 2
319
- # This cop supports unsafe autocorrection (--autocorrect-all).
320
- Style/SelectByKind:
321
- Exclude:
322
- - 'lib/svg_conform/sax_validation_handler.rb'
323
-
324
- # Offense count: 1
325
- # This cop supports unsafe autocorrection (--autocorrect-all).
326
- Style/SelectByRegexp:
327
- Exclude:
328
- - 'lib/svg_conform/remediations/color_remediation.rb'
329
-
330
- # Offense count: 1
331
- # This cop supports safe autocorrection (--autocorrect).
332
- Style/SuperArguments:
333
- Exclude:
334
- - 'lib/svg_conform/requirements/invalid_id_references_requirement.rb'
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"
@@ -0,0 +1,212 @@
1
+ # SVG Quality Metrics Configuration
2
+ #
3
+ # This file defines the quality scoring system for SVG files.
4
+ # Customize these values to adjust how quality scores are calculated.
5
+ #
6
+ # The configuration supports:
7
+ # - Severity level definitions for different violation types
8
+ # - Remediation classification (remediable vs non-remediable errors)
9
+ # - Quality score formula weights
10
+ # - Quality level score thresholds
11
+ # - Size category thresholds
12
+ # - Complexity index calculation
13
+ # - Feature detection patterns
14
+
15
+ # ============================================================================
16
+ # Severity Level Definitions
17
+ # ============================================================================
18
+ # Each severity level defines which violation types fall into it,
19
+ # the default weight per error, and the maximum penalty for that level.
20
+ #
21
+ # Scores are calculated as: error_count * weight, capped at max_penalty
22
+
23
+ severity_levels:
24
+ critical:
25
+ description: "Breaks document validity or breaks links (broken references, structural issues)"
26
+ violation_types:
27
+ - :reference_violation # Broken ID references (xlink:href to missing IDs)
28
+ - :structural_violation # Root element wrong, malformed XML, invalid document
29
+ default_weight: 5
30
+ max_penalty: 20
31
+
32
+ high:
33
+ description: "Breaks rendering or poses security risks"
34
+ violation_types:
35
+ - :viewbox_violation # Missing or malformed viewBox
36
+ - :namespace_violation # Invalid or disallowed namespaces
37
+ - :content_violation # Forbidden elements (script, iframe, etc.)
38
+ default_weight: 3
39
+ max_penalty: 15
40
+
41
+ medium:
42
+ description: "Visual or formatting issues"
43
+ violation_types:
44
+ - :color_violation # Non-standard colors
45
+ - :font_violation # Non-standard fonts
46
+ default_weight: 1
47
+ max_penalty: 10
48
+
49
+ low:
50
+ description: "Informational - style promotion opportunities"
51
+ violation_types:
52
+ - :style_violation # CSS properties that could be promoted to attributes
53
+ default_weight: 0
54
+ max_penalty: 0
55
+
56
+ # ============================================================================
57
+ # Remediation Classification
58
+ # ============================================================================
59
+ # Defines which violation types can be automatically fixed vs require human
60
+ # intervention.
61
+
62
+ # Violation types that can be auto-fixed
63
+ remediable_types:
64
+ - :color_violation
65
+ - :font_violation
66
+ - :content_violation
67
+ - :reference_violation
68
+ - :namespace_violation
69
+ - :viewbox_violation
70
+ - :style_violation
71
+
72
+ # Violation types that require manual intervention
73
+ non_remediable_types:
74
+ - :structural_violation
75
+
76
+ # ============================================================================
77
+ # Quality Score Formula
78
+ # ============================================================================
79
+ # Weights used in the quality score calculation (0-100 scale)
80
+ #
81
+ # Formula:
82
+ # base_score = 100
83
+ # base_score -= (error_density * error_density_weight).clamp(0, error_density_max_penalty)
84
+ # base_score -= non_remediable_count * non_remediable_weight
85
+ # base_score -= critical_count * critical_weight
86
+ # base_score -= high_count * high_weight
87
+ # base_score += valid_structure_bonus if error_count == 0
88
+
89
+ quality_formula:
90
+ # Error density penalty (errors per KB)
91
+ error_density_weight: 8
92
+ error_density_max_penalty: 40
93
+
94
+ # Per-error penalties
95
+ non_remediable_weight: 6
96
+ non_remediable_max_penalty: 30
97
+
98
+ critical_weight: 5
99
+ critical_max_penalty: 20
100
+
101
+ high_weight: 3
102
+ high_max_penalty: 15
103
+
104
+ # Bonus for error-free files
105
+ valid_structure_bonus: 10
106
+
107
+ # ============================================================================
108
+ # Quality Level Thresholds
109
+ # ============================================================================
110
+ # Score ranges for each quality level
111
+
112
+ quality_levels:
113
+ excellent:
114
+ min_score: 90
115
+ max_score: 100
116
+ description: "No errors or minor style issues only"
117
+
118
+ good:
119
+ min_score: 70
120
+ max_score: 89
121
+ description: "Few easily fixable issues"
122
+
123
+ fair:
124
+ min_score: 50
125
+ max_score: 69
126
+ description: "Multiple remediable issues"
127
+
128
+ poor:
129
+ min_score: 30
130
+ max_score: 49
131
+ description: "Some non-remediable issues or many errors"
132
+
133
+ critical:
134
+ min_score: 0
135
+ max_score: 29
136
+ description: "Major structural problems or many critical errors"
137
+
138
+ # ============================================================================
139
+ # Size Category Thresholds
140
+ # ============================================================================
141
+ # File size thresholds in KB
142
+
143
+ size_categories:
144
+ tiny: 5 # < 5 KB
145
+ small: 20 # 5-20 KB
146
+ medium: 100 # 20-100 KB
147
+ large: 500 # 100-500 KB
148
+ # > 500 KB = huge
149
+
150
+ # ============================================================================
151
+ # Complexity Index Calculation
152
+ # ============================================================================
153
+ # Complexity is scored on a 1-10 scale based on element count, nesting depth,
154
+ # and use of advanced SVG features.
155
+
156
+ complexity:
157
+ # Base multiplier for element count
158
+ base_element_multiplier: 0.5
159
+
160
+ # Weight for maximum nesting depth
161
+ depth_weight: 0.1
162
+
163
+ # Bonuses for using advanced features
164
+ feature_bonuses:
165
+ has_masks: 1.0
166
+ has_clip_paths: 0.5
167
+ has_base64: 1.5
168
+ has_foreign_ns: 0.5
169
+ has_external_refs: 0.5
170
+
171
+ # Maximum complexity score
172
+ max_index: 10
173
+
174
+ # ============================================================================
175
+ # Feature Detection Patterns
176
+ # ============================================================================
177
+ # Regex patterns for detecting SVG features in raw content.
178
+ # Used for quick feature flags before full parsing.
179
+
180
+ feature_patterns:
181
+ # Base64 encoded images
182
+ base64: "(?:data:image|ImageUri).*base64.*"
183
+
184
+ # Foreign namespaces (anything not svg/xlink)
185
+ foreign_ns: 'xmlns:(?!svg|xlink)'
186
+
187
+ # Mask elements
188
+ masks: "<[\\s]*mask[\\s\\S]*?>"
189
+
190
+ # Clip path elements
191
+ clip_paths: "<[\\s]*clipPath[\\s\\S]*?>"
192
+
193
+ # External references (http/https URLs in href/xlink:href)
194
+ external_refs: "(?:xlink:)?href.*https?://"
195
+
196
+ # ============================================================================
197
+ # Content Health Thresholds
198
+ # ============================================================================
199
+ # Rules for determining content health status
200
+
201
+ content_health:
202
+ # Minor issues: few low/medium errors only
203
+ minor_issues_max_errors: 10
204
+ minor_issues_max_severity: medium
205
+
206
+ # Moderate issues: more errors OR any high-severity
207
+ moderate_issues_max_errors: 50
208
+ moderate_issues_any_high: true
209
+
210
+ # Severe issues: many errors OR any critical
211
+ severe_issues_min_errors: 50
212
+ severe_issues_any_critical: true