claricle 0.1.0 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -1
- data/LICENSE +25 -0
- data/README.adoc +439 -157
- data/TODO.plan/00-overview.md +502 -0
- data/TODO.plan/01-core.md +296 -0
- data/TODO.plan/02-inspect.md +163 -0
- data/TODO.plan/03-conform.md +208 -0
- data/TODO.plan/04-convert.md +216 -0
- data/exe/claricle +1 -1
- data/lib/claricle/batch.rb +240 -0
- data/lib/claricle/cli.rb +514 -40
- data/lib/claricle/conformance_options.rb +49 -0
- data/lib/claricle/conversion_engine.rb +21 -0
- data/lib/claricle/convert.rb +21 -0
- data/lib/claricle/detector.rb +696 -0
- data/lib/claricle/emf_header.rb +33 -0
- data/lib/claricle/errors.rb +73 -0
- data/lib/claricle/fault.rb +69 -0
- data/lib/claricle/handlers/base.rb +169 -0
- data/lib/claricle/handlers/extension_points.rb +124 -0
- data/lib/claricle/handlers/metafile.rb +1011 -0
- data/lib/claricle/handlers/pdf.rb +961 -0
- data/lib/claricle/handlers/pdf_arlington/definitions.rb +54 -0
- data/lib/claricle/handlers/pdf_arlington/kind.rb +62 -0
- data/lib/claricle/handlers/pdf_arlington/predicate_gate.rb +39 -0
- data/lib/claricle/handlers/pdf_arlington/rules.rb +86 -0
- data/lib/claricle/handlers/pdf_arlington/walker.rb +131 -0
- data/lib/claricle/handlers/pdf_arlington.rb +38 -0
- data/lib/claricle/handlers/pdf_profiles.rb +66 -0
- data/lib/claricle/handlers/png.rb +1107 -0
- data/lib/claricle/handlers/postscript.rb +1357 -0
- data/lib/claricle/handlers/svg.rb +787 -0
- data/lib/claricle/image.rb +272 -0
- data/lib/claricle/lossiness/levels.rb +13 -0
- data/lib/claricle/lossiness.rb +864 -0
- data/lib/claricle/models/base.rb +460 -0
- data/lib/claricle/models/batch_item.rb +127 -0
- data/lib/claricle/models/conversion.rb +167 -0
- data/lib/claricle/models/format_capability.rb +40 -0
- data/lib/claricle/models/free_form_hash.rb +77 -0
- data/lib/claricle/models/inspection.rb +188 -0
- data/lib/claricle/models/issue.rb +23 -0
- data/lib/claricle/models/location.rb +51 -0
- data/lib/claricle/models/report.rb +54 -0
- data/lib/claricle/models/uncoerced_integer.rb +38 -0
- data/lib/claricle/postscript_fidelity/verdict.rb +37 -0
- data/lib/claricle/postscript_fidelity/view_box.rb +82 -0
- data/lib/claricle/postscript_fidelity.rb +160 -0
- data/lib/claricle/registry.rb +125 -0
- data/lib/claricle/version.rb +1 -1
- data/lib/claricle/writer.rb +468 -0
- data/lib/claricle.rb +244 -7
- metadata +201 -19
- data/claricle.gemspec +0 -42
- data/sig/claricle.rbs +0 -4
data/lib/claricle.rb
CHANGED
|
@@ -2,15 +2,252 @@
|
|
|
2
2
|
|
|
3
3
|
require "thor"
|
|
4
4
|
require_relative "claricle/version"
|
|
5
|
+
require_relative "claricle/errors"
|
|
6
|
+
require_relative "claricle/models/location"
|
|
7
|
+
require_relative "claricle/models/issue"
|
|
8
|
+
require_relative "claricle/models/report"
|
|
9
|
+
require_relative "claricle/models/inspection"
|
|
10
|
+
require_relative "claricle/lossiness"
|
|
11
|
+
require_relative "claricle/models/conversion"
|
|
12
|
+
require_relative "claricle/models/batch_item"
|
|
13
|
+
require_relative "claricle/models/format_capability"
|
|
14
|
+
require_relative "claricle/fault"
|
|
15
|
+
require_relative "claricle/batch"
|
|
16
|
+
require_relative "claricle/writer"
|
|
17
|
+
require_relative "claricle/registry"
|
|
18
|
+
require_relative "claricle/conformance_options"
|
|
19
|
+
require_relative "claricle/detector"
|
|
20
|
+
require_relative "claricle/image"
|
|
21
|
+
require_relative "claricle/cli"
|
|
22
|
+
require_relative "claricle/convert"
|
|
5
23
|
|
|
6
24
|
module Claricle
|
|
7
|
-
|
|
25
|
+
# Detects the format of `source`, a String of image content or an IO.
|
|
26
|
+
#
|
|
27
|
+
# An IO is read from wherever it is currently positioned -- it is never
|
|
28
|
+
# rewound, so a caller who has already consumed part of it gets a
|
|
29
|
+
# verdict on the remainder. Bytes are pulled in incrementally and
|
|
30
|
+
# classification is retried after each read, so a short, conclusive
|
|
31
|
+
# image (its signature or root tag already present) returns without
|
|
32
|
+
# waiting for more. Plain PostScript and EPSF are the exception: a byte
|
|
33
|
+
# that hasn't arrived yet can still turn one into the other, so that
|
|
34
|
+
# verdict waits for the probe bound -- the largest amount any detector
|
|
35
|
+
# probe consults -- or end of stream. A binary-preview EPS has its own
|
|
36
|
+
# conclusive magic and returns immediately. A source that stays open
|
|
37
|
+
# and never supplies enough to decide blocks until one of those is
|
|
38
|
+
# reached; content beyond the bound is left unread on the IO rather
|
|
39
|
+
# than buffered. It should be in binary mode; newline translation
|
|
40
|
+
# would corrupt the signatures this matches on. Pass a path to
|
|
41
|
+
# `Image.from_path` to stream from a file instead of buffering.
|
|
42
|
+
def self.detect(source)
|
|
43
|
+
return Detector.detect(source) unless source.respond_to?(:read)
|
|
8
44
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# require_relative "claricle/svg_processor"
|
|
12
|
-
# require_relative "claricle/vector_converter"
|
|
13
|
-
# require_relative "claricle/image_compressor"
|
|
45
|
+
Detector.detect(accumulate(source))
|
|
46
|
+
end
|
|
14
47
|
|
|
15
|
-
|
|
48
|
+
# Grows `buffer` by reading from `source` a chunk at a time, stopping
|
|
49
|
+
# as soon as the buffer classifies, hits the probe bound, or the
|
|
50
|
+
# source ends -- so a complete short image on a stream that never
|
|
51
|
+
# closes doesn't wait for bytes nothing needs.
|
|
52
|
+
def self.accumulate(source)
|
|
53
|
+
buffer = "".b
|
|
54
|
+
loop do
|
|
55
|
+
return buffer if conclusive?(buffer) || buffer.bytesize >= Detector::MAX_PROBE_BYTES
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
buffer << source.readpartial(Detector::MAX_PROBE_BYTES - buffer.bytesize)
|
|
59
|
+
rescue EOFError
|
|
60
|
+
return buffer
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.conclusive?(buffer)
|
|
66
|
+
return true if EpsBinary.wrapped?(buffer)
|
|
67
|
+
|
|
68
|
+
format = Detector.detect(buffer)
|
|
69
|
+
# A plain PostScript verdict is provisional until the underlying line
|
|
70
|
+
# scan is certain: a byte that hasn't arrived yet can still flip EPSF
|
|
71
|
+
# from a trusted match to a disqualified one, so this loop must not
|
|
72
|
+
# settle for less than a real end of stream or the probe bound.
|
|
73
|
+
!%i[ps eps].include?(format)
|
|
74
|
+
rescue UnknownFormat
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Does everything named here conform? Exactly one of a positional path or
|
|
79
|
+
# `pattern:` -- issue #1's own examples use both shapes.
|
|
80
|
+
#
|
|
81
|
+
# A predicate answers about conformance and raises about everything else.
|
|
82
|
+
# A nonconformant file is `false`; an unknown format, an unsupported one,
|
|
83
|
+
# a missing file or a delegate crash raises, out of the batch shape too,
|
|
84
|
+
# so an operational failure never reads as a verdict.
|
|
85
|
+
#
|
|
86
|
+
# Both shapes reach the same expansion, so a positional means here exactly
|
|
87
|
+
# what it means on the command line: a literal path when it names a file,
|
|
88
|
+
# and a glob otherwise.
|
|
89
|
+
def self.conform?(path = nil, pattern: nil, strict: false, profile: nil, level: nil)
|
|
90
|
+
raise InvocationError, "give exactly one of a path or pattern" unless path.nil? ^ pattern.nil?
|
|
91
|
+
|
|
92
|
+
profile, level = ConformanceOptions.normalize(profile, level)
|
|
93
|
+
result = conformance_batch(*[path].compact, pattern: pattern,
|
|
94
|
+
strict: strict, profile: profile, level: level)
|
|
95
|
+
raise result.highest_error if result.highest_error
|
|
96
|
+
|
|
97
|
+
result.exit_code.zero?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.conformance_report(path, profile: nil, level: nil)
|
|
101
|
+
profile, level = ConformanceOptions.normalize(profile, level)
|
|
102
|
+
Image.from_path(path).conformance_report(profile: profile, level: level)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# A batch predicate loses information, so a caller can have the whole
|
|
106
|
+
# result instead: ordered per-file outcomes plus the aggregate status,
|
|
107
|
+
# which is what the command prints. Takes the command's own argument
|
|
108
|
+
# shape -- files, a pattern, or both -- so the two cannot drift about
|
|
109
|
+
# what conformance means.
|
|
110
|
+
def self.conformance_batch(*paths, pattern: nil, strict: false, profile: nil, level: nil)
|
|
111
|
+
# Checked eagerly here, before the batch runs, so a profile no format
|
|
112
|
+
# defines is one invocation error about the call and never a row in a
|
|
113
|
+
# report -- `conformance_report` checks it again per file, but only as a
|
|
114
|
+
# no-op once this call has already passed.
|
|
115
|
+
profile, level = ConformanceOptions.normalize(profile, level)
|
|
116
|
+
Batch.run(paths, pattern: pattern,
|
|
117
|
+
classify: ->(report) { conformant?(report, strict: strict) ? 0 : 1 }) do |file|
|
|
118
|
+
conformance_report(file, profile: profile, level: level)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Any error means no; a warning alone means suspicious, which passes
|
|
123
|
+
# unless the caller asked for strict; info never downgrades anything.
|
|
124
|
+
def self.conformant?(report, strict:)
|
|
125
|
+
strict ? report.valid == :yes : report.valid != :no
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# A batch predicate loses information, so a caller can have the whole
|
|
129
|
+
# result instead: ordered per-file outcomes plus the aggregate status.
|
|
130
|
+
# Same argument shape as `conformance_batch` (paths, pattern:), plus
|
|
131
|
+
# `to:`/`output:`/`force:` for the target and the write lifecycle, so
|
|
132
|
+
# the CLI command and the Ruby API cannot drift about what "which files"
|
|
133
|
+
# or "where to" mean.
|
|
134
|
+
#
|
|
135
|
+
# The whole destination set is preflighted -- collision, overwrite,
|
|
136
|
+
# case-fold aliasing -- BEFORE any file is converted. That is why this
|
|
137
|
+
# resolves the expanded file list and every destination up front, rather
|
|
138
|
+
# than letting `Batch.run` derive them one file at a time the way
|
|
139
|
+
# `conformance_batch` does.
|
|
140
|
+
#
|
|
141
|
+
# Target resolution runs before the single-source check below, so a
|
|
142
|
+
# `--to`/`--output` mismatch is reported even when the source count is
|
|
143
|
+
# also wrong -- the more specific problem surfaces first rather than
|
|
144
|
+
# being masked by the more generic one.
|
|
145
|
+
def self.convert_batch(*paths, to: nil, output: nil, force: false, pattern: nil)
|
|
146
|
+
files = Batch.expand(paths, pattern)
|
|
147
|
+
target = resolved_convert_target(to: to, output: output)
|
|
148
|
+
raise InvocationError, "--output takes a single source; #{files.length} files matched" if output && files.length > 1
|
|
149
|
+
|
|
150
|
+
destinations = files.to_h { |file| [file, convert_destination(file, target: target, output: output)] }
|
|
151
|
+
writer = Writer.new(destinations.values, sources: files, force: force)
|
|
152
|
+
|
|
153
|
+
# `classify` always answers 0: the block below either returns a
|
|
154
|
+
# `Models::Conversion` normally, or raises, which Batch's own per-file
|
|
155
|
+
# rescue already turns into a failed item with its own exit code. There
|
|
156
|
+
# is no success/failure distinction left for `classify` to make --
|
|
157
|
+
# unlike `Report#valid`, a completed conversion has no verdict to grade.
|
|
158
|
+
#
|
|
159
|
+
# `run_files`, not `run`: `files` is already the expanded list built
|
|
160
|
+
# above for the destination preflight. `run` would expand it a SECOND
|
|
161
|
+
# time -- redundant stat/realpath work on every file, and a real gap:
|
|
162
|
+
# a file removed between the two expansions would silently drop out of
|
|
163
|
+
# the second one with no error, even though a destination was already
|
|
164
|
+
# preflighted for it.
|
|
165
|
+
Batch.run_files(files, classify: ->(_result) { 0 }) do |file|
|
|
166
|
+
convert_one(file, target: target, destination: destinations.fetch(file), writer: writer)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def self.convert_one(file, target:, destination:, writer:)
|
|
171
|
+
image = Image.from_path(file)
|
|
172
|
+
raise InvocationError, "#{file} is already #{target}; nothing to convert to" if image.format == target
|
|
173
|
+
|
|
174
|
+
# See `Models::Conversion#with_output_path` for why a second instance
|
|
175
|
+
# is built here rather than the handler's own carrying the real path.
|
|
176
|
+
conversion = image.convert(to: target)
|
|
177
|
+
conversion.with_output_path(writer.write(conversion.content, to: destination))
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# `--to` wins outright when given, once it does not conflict with a
|
|
181
|
+
# recognised `--output` extension. `--output` alone must name a
|
|
182
|
+
# recognised extension to infer from; `--output -` alone cannot, since
|
|
183
|
+
# stdout has no extension.
|
|
184
|
+
#
|
|
185
|
+
# `--to` is case-folded to the registry's own spelling (`Registry.formats`
|
|
186
|
+
# is always lowercase symbols) so `--to SVG` and `--to svg` resolve
|
|
187
|
+
# identically -- unfolded, `--to SVG --output copy.svg` reported a false
|
|
188
|
+
# "conflicts with --output" (the two sides compared `:SVG` against the
|
|
189
|
+
# inferred `:svg`), a same-format `--to SVG` on an already-SVG source
|
|
190
|
+
# skipped the guard below entirely, and the derived destination for a
|
|
191
|
+
# bare `--to SVG` carried the wrong-cased extension.
|
|
192
|
+
def self.resolved_convert_target(to:, output:)
|
|
193
|
+
# `if to` alone treats an explicit `--to ""` as given: truthy, but
|
|
194
|
+
# `to.to_s.downcase.to_sym` then builds the bogus target `:""`, which
|
|
195
|
+
# went on to derive a destination with no extension and a garbled
|
|
196
|
+
# "not supported for convert to :\"\"" message instead of the clean
|
|
197
|
+
# invocation error below. `--to ""` and no `--to` at all mean the same
|
|
198
|
+
# thing -- there is no target -- so both take this branch.
|
|
199
|
+
return resolved_to_target(to, output) if to && !to.to_s.empty?
|
|
200
|
+
if output == Writer::STDOUT_DESTINATION
|
|
201
|
+
raise InvocationError, "--output - needs --to; there is no extension to infer from"
|
|
202
|
+
end
|
|
203
|
+
raise InvocationError, "give --to, or an --output with a recognised format extension" if output.nil?
|
|
204
|
+
|
|
205
|
+
convert_extension_format(output) ||
|
|
206
|
+
raise(InvocationError, "--output #{output.inspect} has no recognised format extension; give --to")
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def self.resolved_to_target(to, output)
|
|
210
|
+
target = to.to_s.downcase.to_sym
|
|
211
|
+
raise InvocationError, "unknown format #{to.to_s.inspect} for --to" unless Registry.formats.include?(target)
|
|
212
|
+
|
|
213
|
+
check_to_output_conflict(target, output)
|
|
214
|
+
target
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# A conflict, not a preference: one silently winning over the other would
|
|
218
|
+
# surprise whichever the caller meant. `output:` naming stdout or an
|
|
219
|
+
# unrecognised extension carries no claim about the target, so there is
|
|
220
|
+
# nothing for `--to` to conflict with in either case. `target` arrives
|
|
221
|
+
# already case-folded from `resolved_convert_target`.
|
|
222
|
+
def self.check_to_output_conflict(target, output)
|
|
223
|
+
return if output.nil? || output == Writer::STDOUT_DESTINATION
|
|
224
|
+
|
|
225
|
+
inferred = convert_extension_format(output)
|
|
226
|
+
return if inferred.nil? || inferred == target
|
|
227
|
+
|
|
228
|
+
raise InvocationError, "--to #{target} conflicts with --output #{output} (looks like #{inferred})"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# The canonical extension for a target is the format symbol itself --
|
|
232
|
+
# there is no central extension table, only `Registry.formats`.
|
|
233
|
+
def self.convert_extension_format(name)
|
|
234
|
+
ext = File.extname(name.to_s).delete_prefix(".").downcase
|
|
235
|
+
return nil if ext.empty?
|
|
236
|
+
|
|
237
|
+
format = ext.to_sym
|
|
238
|
+
Registry.formats.include?(format) ? format : nil
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# The issue's own example: `convert("diagram.emf", to: :svg)` writes
|
|
242
|
+
# `diagram.svg` -- the source's own name, the target's extension,
|
|
243
|
+
# alongside the source.
|
|
244
|
+
def self.convert_destination(file, target:, output:)
|
|
245
|
+
return output if output
|
|
246
|
+
|
|
247
|
+
File.join(File.dirname(file), "#{File.basename(file, ".*")}.#{target}")
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
private_class_method :accumulate, :conclusive?, :conformant?,
|
|
251
|
+
:convert_one, :resolved_convert_target, :resolved_to_target,
|
|
252
|
+
:check_to_output_conflict, :convert_extension_format, :convert_destination
|
|
16
253
|
end
|
metadata
CHANGED
|
@@ -1,36 +1,175 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claricle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-10-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: emf
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.1.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.1.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: emfsvg
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.1.2
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.1.2
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: lutaml-model
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 0.8.32
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.8.32
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: pdfrb
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 0.7.23
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 0.7.23
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: png_conform
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 0.1.4
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 0.1.4
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: postscript
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 0.2.0
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 0.2.0
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: postsvg
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: 0.3.0
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: 0.3.0
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rexml
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: 3.4.4
|
|
118
|
+
type: :runtime
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: 3.4.4
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: svg_conform
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: 0.2.2
|
|
132
|
+
type: :runtime
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: 0.2.2
|
|
13
139
|
- !ruby/object:Gem::Dependency
|
|
14
140
|
name: thor
|
|
15
141
|
requirement: !ruby/object:Gem::Requirement
|
|
16
142
|
requirements:
|
|
17
143
|
- - "~>"
|
|
18
144
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
145
|
+
version: '1.2'
|
|
146
|
+
type: :runtime
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '1.2'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: vectory
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "~>"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: 0.12.0
|
|
20
160
|
type: :runtime
|
|
21
161
|
prerelease: false
|
|
22
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
163
|
requirements:
|
|
24
164
|
- - "~>"
|
|
25
165
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
166
|
+
version: 0.12.0
|
|
27
167
|
description: |
|
|
28
|
-
Claricle
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
a unified interface.
|
|
168
|
+
Claricle detects an image's format from its bytes -- PNG, SVG, EMF, WMF,
|
|
169
|
+
EPS, PS and PDF -- and gives one object and one set of models to work with.
|
|
170
|
+
The name combines "clarity" and "particle". It inspects, checks
|
|
171
|
+
conformance and converts between formats, wrapping
|
|
172
|
+
png_conform, svg_conform, vectory and pdfrb behind a single interface.
|
|
34
173
|
email:
|
|
35
174
|
- open.source@ribose.com
|
|
36
175
|
executables:
|
|
@@ -42,21 +181,65 @@ files:
|
|
|
42
181
|
- ".rubocop.yml"
|
|
43
182
|
- CODE_OF_CONDUCT.md
|
|
44
183
|
- Gemfile
|
|
184
|
+
- LICENSE
|
|
45
185
|
- README.adoc
|
|
46
186
|
- Rakefile
|
|
47
|
-
-
|
|
187
|
+
- TODO.plan/00-overview.md
|
|
188
|
+
- TODO.plan/01-core.md
|
|
189
|
+
- TODO.plan/02-inspect.md
|
|
190
|
+
- TODO.plan/03-conform.md
|
|
191
|
+
- TODO.plan/04-convert.md
|
|
48
192
|
- exe/claricle
|
|
49
193
|
- lib/claricle.rb
|
|
194
|
+
- lib/claricle/batch.rb
|
|
50
195
|
- lib/claricle/cli.rb
|
|
196
|
+
- lib/claricle/conformance_options.rb
|
|
197
|
+
- lib/claricle/conversion_engine.rb
|
|
198
|
+
- lib/claricle/convert.rb
|
|
199
|
+
- lib/claricle/detector.rb
|
|
200
|
+
- lib/claricle/emf_header.rb
|
|
201
|
+
- lib/claricle/errors.rb
|
|
202
|
+
- lib/claricle/fault.rb
|
|
203
|
+
- lib/claricle/handlers/base.rb
|
|
204
|
+
- lib/claricle/handlers/extension_points.rb
|
|
205
|
+
- lib/claricle/handlers/metafile.rb
|
|
206
|
+
- lib/claricle/handlers/pdf.rb
|
|
207
|
+
- lib/claricle/handlers/pdf_arlington.rb
|
|
208
|
+
- lib/claricle/handlers/pdf_arlington/definitions.rb
|
|
209
|
+
- lib/claricle/handlers/pdf_arlington/kind.rb
|
|
210
|
+
- lib/claricle/handlers/pdf_arlington/predicate_gate.rb
|
|
211
|
+
- lib/claricle/handlers/pdf_arlington/rules.rb
|
|
212
|
+
- lib/claricle/handlers/pdf_arlington/walker.rb
|
|
213
|
+
- lib/claricle/handlers/pdf_profiles.rb
|
|
214
|
+
- lib/claricle/handlers/png.rb
|
|
215
|
+
- lib/claricle/handlers/postscript.rb
|
|
216
|
+
- lib/claricle/handlers/svg.rb
|
|
217
|
+
- lib/claricle/image.rb
|
|
218
|
+
- lib/claricle/lossiness.rb
|
|
219
|
+
- lib/claricle/lossiness/levels.rb
|
|
220
|
+
- lib/claricle/models/base.rb
|
|
221
|
+
- lib/claricle/models/batch_item.rb
|
|
222
|
+
- lib/claricle/models/conversion.rb
|
|
223
|
+
- lib/claricle/models/format_capability.rb
|
|
224
|
+
- lib/claricle/models/free_form_hash.rb
|
|
225
|
+
- lib/claricle/models/inspection.rb
|
|
226
|
+
- lib/claricle/models/issue.rb
|
|
227
|
+
- lib/claricle/models/location.rb
|
|
228
|
+
- lib/claricle/models/report.rb
|
|
229
|
+
- lib/claricle/models/uncoerced_integer.rb
|
|
230
|
+
- lib/claricle/postscript_fidelity.rb
|
|
231
|
+
- lib/claricle/postscript_fidelity/verdict.rb
|
|
232
|
+
- lib/claricle/postscript_fidelity/view_box.rb
|
|
233
|
+
- lib/claricle/registry.rb
|
|
51
234
|
- lib/claricle/version.rb
|
|
52
|
-
-
|
|
53
|
-
homepage: https://github.com/
|
|
235
|
+
- lib/claricle/writer.rb
|
|
236
|
+
homepage: https://github.com/claricle/claricle
|
|
54
237
|
licenses:
|
|
55
238
|
- BSD-2-Clause
|
|
56
239
|
metadata:
|
|
57
|
-
homepage_uri: https://github.com/
|
|
58
|
-
source_code_uri: https://github.com/
|
|
59
|
-
changelog_uri: https://github.com/
|
|
240
|
+
homepage_uri: https://github.com/claricle/claricle
|
|
241
|
+
source_code_uri: https://github.com/claricle/claricle
|
|
242
|
+
changelog_uri: https://github.com/claricle/claricle/releases
|
|
60
243
|
rubygems_mfa_required: 'true'
|
|
61
244
|
post_install_message:
|
|
62
245
|
rdoc_options: []
|
|
@@ -66,7 +249,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
66
249
|
requirements:
|
|
67
250
|
- - ">="
|
|
68
251
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: 3.
|
|
252
|
+
version: 3.3.0
|
|
70
253
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
254
|
requirements:
|
|
72
255
|
- - ">="
|
|
@@ -76,6 +259,5 @@ requirements: []
|
|
|
76
259
|
rubygems_version: 3.5.22
|
|
77
260
|
signing_key:
|
|
78
261
|
specification_version: 4
|
|
79
|
-
summary:
|
|
80
|
-
and compression.
|
|
262
|
+
summary: Detect, inspect, conform and convert image files in Ruby.
|
|
81
263
|
test_files: []
|
data/claricle.gemspec
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/claricle/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "claricle"
|
|
7
|
-
spec.version = Claricle::VERSION
|
|
8
|
-
spec.authors = ["Ribose Inc."]
|
|
9
|
-
spec.email = ["open.source@ribose.com"]
|
|
10
|
-
|
|
11
|
-
spec.summary = "Claricle is a comprehensive image utility gem for validation, conversion, and compression."
|
|
12
|
-
spec.description = <<~HEREDOC
|
|
13
|
-
Claricle provides a Ruby library for working with images, offering tools for
|
|
14
|
-
image validation (PNG, SVG), format conversion, compression, and vector
|
|
15
|
-
graphics processing. The name combines "clarity" and "particle", representing
|
|
16
|
-
the clear validation of every pixel. It is built to integrate functionality
|
|
17
|
-
from pngconform, svgconform, vectory, and other image processing tools into
|
|
18
|
-
a unified interface.
|
|
19
|
-
HEREDOC
|
|
20
|
-
|
|
21
|
-
spec.homepage = "https://github.com/ribose/claricle"
|
|
22
|
-
spec.license = "BSD-2-Clause"
|
|
23
|
-
spec.required_ruby_version = ">= 3.0.0"
|
|
24
|
-
|
|
25
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
26
|
-
spec.metadata["source_code_uri"] = "https://github.com/ribose/claricle"
|
|
27
|
-
spec.metadata["changelog_uri"] = "https://github.com/ribose/claricle"
|
|
28
|
-
spec.metadata["rubygems_mfa_required"] = "true"
|
|
29
|
-
|
|
30
|
-
# Specify which files should be added to the gem when it is released.
|
|
31
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
32
|
-
spec.files = Dir.chdir(__dir__) do
|
|
33
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
34
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
spec.bindir = "exe"
|
|
38
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
39
|
-
spec.require_paths = ["lib"]
|
|
40
|
-
|
|
41
|
-
spec.add_dependency "thor", "~> 1.0"
|
|
42
|
-
end
|
data/sig/claricle.rbs
DELETED