metanorma-utils 1.6.5 → 1.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3f777cb3ba87e217a3b56ee8caf1a2cd8f6948a8664e18900c6eb5494d162f9
4
- data.tar.gz: 6a758b7d70a52f55c71d8db3562ea32a0f19de514948d17a48bee811850e0b16
3
+ metadata.gz: d976aa0a315c0de6418c649e96065e3b5f0792a232e55ed9b2a6044ed7257491
4
+ data.tar.gz: 50829e2e03b2c4da90cbccf7773309c4e6a88dfc5e3eaeb9d93f33608fe36539
5
5
  SHA512:
6
- metadata.gz: 2bf9b223b840ea02f05c3fe37cc6d12ab73044da84f5108c5f94323a096a567934deec55ddce269f616382b09e98f2be1bc8d835120b6127549ee3febd00bcaf
7
- data.tar.gz: 5447a68582a1c245e1d8a1763573b956ae5999e7ed3a4b8f057e57b301cdc16d5cf2db99fa64bcdd6cb9f0047114fb75b812232fca7303c49ee9095a72387646
6
+ metadata.gz: fbee4963987764258501a416f9cf662612240b15f53f169fe2f104738d8bda20c83f9fa7a782077e9668b9764ea1ac968a6a155709e0bc4d04bc15f0a8a2507c
7
+ data.tar.gz: e25371b4a3c0efa083a7086495207fede9ac7c8df0524b49a5951f83557e8367ecbf52de7aea34d0cb73103180acc077e0afe9b6fe964816aa42c49d1cda339f
data/Gemfile CHANGED
@@ -4,12 +4,6 @@ Encoding.default_internal = Encoding::UTF_8
4
4
  source "https://rubygems.org"
5
5
  git_source(:github) { |repo| "https://github.com/#{repo}" }
6
6
 
7
- group :development, :test do
8
- gem "rspec"
9
- end
10
-
11
- if File.exist? "Gemfile.devel"
12
- eval File.read("Gemfile.devel"), nil, "Gemfile.devel" # rubocop:disable Security/Eval
13
- end
14
-
15
7
  gemspec
8
+
9
+ eval_gemfile("Gemfile.devel") rescue nil
data/lib/utils/image.rb CHANGED
@@ -1,187 +1,68 @@
1
1
  require "tempfile"
2
2
  require "marcel"
3
3
  require "base64"
4
+ require "image_size"
5
+ require_relative "namespace"
4
6
 
5
7
  module Metanorma
6
8
  module Utils
7
9
  class << self
8
- class Namespace
9
- def initialize(xmldoc)
10
- @namespace = xmldoc.root.namespace
11
- end
12
-
13
- def ns(path)
14
- return path if @namespace.nil?
15
-
16
- path.gsub(%r{/([a-zA-z])}, "/xmlns:\\1")
17
- .gsub(%r{::([a-zA-z])}, "::xmlns:\\1")
18
- .gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1")
19
- .gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
20
- end
21
- end
22
-
23
- def save_dataimage(uri)
24
- %r{^data:(?:image|application)/(?<imgtype>[^;]+);(?:charset=[^;]+;)?base64,(?<imgdata>.+)$} =~ uri
25
- imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
26
- imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
27
- Tempfile.open(["image", ".#{imgtype}"]) do |f|
28
- f.binmode
29
- f.write(Base64.strict_decode64(imgdata))
30
- f.path
31
- end
32
- end
33
-
34
- SVG_NS = "http://www.w3.org/2000/svg".freeze
35
-
36
- def svgmap_rewrite(xmldoc, localdirectory = "")
37
- n = Namespace.new(xmldoc)
38
- xmldoc.xpath(n.ns("//svgmap")).each_with_index do |s, i|
39
- next unless svgmap_rewrite0(s, n, localdirectory, i)
40
- next if s.at(n.ns("./target/eref"))
41
-
42
- s.replace(s.at(n.ns("./figure")))
43
- end
44
- end
45
-
46
- def svgmap_rewrite0(svgmap, namespace, localdirectory, idx)
47
- if (i = svgmap.at(namespace.ns(".//image"))) &&
48
- (src = i["src"]) && !src.empty?
49
- path = svgmap_rewrite0_path(src, localdirectory)
50
- File.file?(path) or return false
51
- svg = Nokogiri::XML(File.read(path, encoding: "utf-8"))
52
- i.replace(svgmap_rewrite1(svgmap, svg.root, namespace, idx))
53
- /^data:/.match(src) and i["src"] = datauri(path)
54
- elsif i = svgmap.at(".//m:svg", "m" => SVG_NS)
55
- i.replace(svgmap_rewrite1(svgmap, i, namespace, idx))
56
- else return false
57
- end
58
- true
10
+ def image_resize(img, path, maxheight, maxwidth)
11
+ s, realsize = get_image_size(img, path)
12
+ img.name == "svg" && !img["viewBox"] && s[0] && s[1] and
13
+ img["viewBox"] = "0 0 #{s[0]} #{s[1]}"
14
+ s, skip = image_dont_resize(s, realsize)
15
+ skip and return s
16
+ s = image_size_fillin(s, realsize)
17
+ image_shrink(s, maxheight, maxwidth)
59
18
  end
60
19
 
61
- def svgmap_rewrite0_path(src, localdirectory)
62
- if /^data:/.match?(src)
63
- save_dataimage(src)
64
- else
65
- File.file?(src) ? src : localdirectory + src
66
- end
20
+ def image_dont_resize(dim, realsize)
21
+ dim.nil? and return [[nil, nil], true]
22
+ realsize.nil? and return [dim, true]
23
+ dim[0] == nil && dim[1] == nil and return [dim, true]
24
+ [dim, false]
67
25
  end
68
26
 
69
- def svgmap_rewrite1(svgmap, svg, namespace, idx)
70
- svg_update_href(svgmap, svg, namespace)
71
- svg_update_ids(svg, idx)
72
- svg.xpath("processing-instruction()|.//processing-instruction()").remove
73
- svg.to_xml
27
+ def image_size_fillin(dim, realsize)
28
+ dim[1].zero? && !dim[0].zero? and
29
+ dim[1] = dim[0] * realsize[1] / realsize[0]
30
+ dim[0].zero? && !dim[1].zero? and
31
+ dim[0] = dim[1] * realsize[0] / realsize[1]
32
+ dim
74
33
  end
75
34
 
76
- def svg_update_href(svgmap, svg, namespace)
77
- targ = svgmap_rewrite1_targets(svgmap, namespace)
78
- svg.xpath(".//m:a", "m" => SVG_NS).each do |a|
79
- ["xlink:href", "href"].each do |p|
80
- a[p] and x = targ[File.expand_path(a[p])] and a[p] = x
81
- end
82
- end
35
+ def image_shrink(dim, maxheight, maxwidth)
36
+ dim[1] > maxheight and
37
+ dim = [(dim[0] * maxheight / dim[1]).ceil, maxheight]
38
+ dim[0] > maxwidth and
39
+ dim = [maxwidth, (dim[1] * maxwidth / dim[0]).ceil]
40
+ dim
83
41
  end
84
42
 
85
- def svgmap_rewrite1_targets(svgmap, namespace)
86
- svgmap.xpath(namespace.ns("./target"))
87
- .each_with_object({}) do |t, m|
88
- x = t.at(namespace.ns("./xref")) and
89
- m[File.expand_path(t["href"])] = "##{x['target']}"
90
- x = t.at(namespace.ns("./link")) and
91
- m[File.expand_path(t["href"])] = x["target"]
92
- t.remove if t.at(namespace.ns("./xref | ./link"))
93
- end
43
+ def get_image_size(img, path)
44
+ realsize = ImageSize.path(path).size
45
+ s = image_size_interpret(img, realsize || [nil, nil])
46
+ image_size_zeroes_complete(s, realsize)
94
47
  end
95
48
 
96
- def svg_update_ids(svg, idx)
97
- ids = svg.xpath("./@id | .//@id")
98
- .each_with_object([]) { |i, m| m << i.value }
99
- return if ids.empty?
100
-
101
- svg_update_ids_attrs(svg, ids, idx)
102
- svg_update_ids_css(svg, ids, idx)
49
+ def image_size_interpret(img, realsize)
50
+ w = image_size_percent(img["width"], realsize[0])
51
+ h = image_size_percent(img["height"], realsize[1])
52
+ [w, h]
103
53
  end
104
54
 
105
- def svg_update_ids_attrs(svg, ids, idx)
106
- svg.xpath(". | .//*[@*]").each do |a|
107
- a.attribute_nodes.each do |x|
108
- ids.include?(x.value) and x.value += sprintf("_%09d", idx)
109
- end
110
- end
55
+ def image_size_percent(value, real)
56
+ /%$/.match?(value) && !real.nil? and
57
+ value = real * (value.sub(/%$/, "").to_f / 100)
58
+ value.to_i
111
59
  end
112
60
 
113
- def svg_update_ids_css(svg, ids, idx)
114
- svg.xpath("//m:style", "m" => SVG_NS).each do |s|
115
- c = s.children.to_xml
116
- ids.each do |i|
117
- c = c.gsub(%r[##{i}\b],
118
- sprintf("#%<id>s_%<idx>09d", id: i, idx: idx))
119
- .gsub(%r(\[id\s*=\s*['"]?#{i}['"]?\]),
120
- sprintf("[id='%<id>s_%<idx>09d']", id: i, idx: idx))
121
- end
122
- s.children = c
61
+ def image_size_zeroes_complete(dim, realsize)
62
+ if dim[0].zero? && dim[1].zero?
63
+ dim = realsize
123
64
  end
124
- end
125
-
126
- # sources/plantuml/plantuml20200524-90467-1iqek5i.png
127
- # already includes localdir
128
- # Check whether just the local path or the other specified relative path
129
- # works.
130
- def datauri(uri, local_dir = ".")
131
- (datauri?(uri) || url?(uri)) and return uri
132
- options = absolute_path?(uri) ? [uri] : [uri, File.join(local_dir, uri)]
133
- path = options.detect do |p|
134
- File.exist?(p) ? p : nil
135
- end
136
- path and return encode_datauri(path)
137
- warn "Image specified at `#{uri}` does not exist."
138
- uri # Return original provided location
139
- end
140
-
141
- def encode_datauri(path)
142
- return nil unless File.exist?(path)
143
-
144
- type = Marcel::MimeType.for(Pathname.new(path)) ||
145
- 'text/plain; charset="utf-8"'
146
-
147
- bin = File.binread(path)
148
- data = Base64.strict_encode64(bin)
149
- "data:#{type};base64,#{data}"
150
- rescue StandardError
151
- warn "Data-URI encoding of `#{path}` failed."
152
- nil
153
- end
154
-
155
- def datauri?(uri)
156
- /^data:/.match?(uri)
157
- end
158
-
159
- def url?(url)
160
- %r{^[A-Z]{2,}://}i.match?(url)
161
- end
162
-
163
- def absolute_path?(uri)
164
- %r{^/}.match?(uri) || %r{^[A-Z]:/}.match?(uri)
165
- end
166
-
167
- def decode_datauri(uri)
168
- %r{^data:(?<mimetype>[^;]+);base64,(?<mimedata>.+)$} =~ uri
169
- return nil unless mimetype && mimedata
170
-
171
- data = Base64.strict_decode64(mimedata)
172
- {
173
- type_declared: mimetype,
174
- type_detected: Marcel::MimeType.for(data, declared_type: mimetype),
175
- data: data,
176
- }
177
- end
178
-
179
- # FIXME: This method should ONLY return 1 type, remove Array wrapper
180
- def datauri2mime(uri)
181
- output = decode_datauri(uri)
182
- return nil unless output && output[:type_detected]
183
-
184
- [output[:type_detected]]
65
+ [dim, realsize]
185
66
  end
186
67
  end
187
68
  end
@@ -0,0 +1,26 @@
1
+ module Metanorma
2
+ module Utils
3
+ class << self
4
+ # NOTE: It was used in methods of an eigenclass of Metanorma::Utils.
5
+ # Not sure if it's still used somewhere but could be.
6
+ class Namespace
7
+ def initialize(xmldoc)
8
+ @namespace = xmldoc.root.namespace
9
+ end
10
+
11
+ def ns(path)
12
+ return path if @namespace.nil?
13
+
14
+ path.gsub(%r{/([a-zA-Z])}, "/xmlns:\\1")
15
+ .gsub(%r{::([a-zA-Z])}, "::xmlns:\\1")
16
+ .gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1")
17
+ .gsub(%r{\[([a-zA-Z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
18
+ end
19
+ end
20
+
21
+ def create_namespace(xmldoc)
22
+ Namespace.new(xmldoc)
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/utils/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Metanorma
2
2
  module Utils
3
- VERSION = "1.6.5".freeze
3
+ VERSION = "1.7.0".freeze
4
4
  end
5
5
  end
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency "concurrent-ruby"
31
31
  spec.add_dependency "csv"
32
32
  spec.add_dependency "htmlentities", "~> 4.3.4"
33
+ spec.add_dependency "image_size", ">= 3.2.0"
33
34
  spec.add_dependency "marcel", "~> 1.0.0"
34
35
  spec.add_dependency "mime-types"
35
36
  spec.add_dependency "nokogiri", ">= 1.11"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.5
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-07 00:00:00.000000000 Z
11
+ date: 2024-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 4.3.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: image_size
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 3.2.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 3.2.0
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: marcel
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -324,6 +338,7 @@ files:
324
338
  - lib/utils/image.rb
325
339
  - lib/utils/log.rb
326
340
  - lib/utils/main.rb
341
+ - lib/utils/namespace.rb
327
342
  - lib/utils/version.rb
328
343
  - lib/utils/xml.rb
329
344
  - metanorma-utils.gemspec