metanorma-utils 1.0.8 → 1.2.2

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: 366ab5765fb28315b8c4258b6d766b04733ffbc69c912fd718f2229a5d5a9303
4
- data.tar.gz: abdcfed1228161a42c79d748b4a50b36ef29c08f9b028c1ee86ce14b053db482
3
+ metadata.gz: 52b94adefc23d35f664e35438604432f951f29d15ccb5622f64447a79eaa14d0
4
+ data.tar.gz: 5e68045ce2aaf9c6a34ec8793d8f75b1e3bb065fe4a733db84101f4bee31cf2d
5
5
  SHA512:
6
- metadata.gz: 620d77ee112d112ee72e2fc90257692ff39120f6fa0e2e8d219e0a2790435e750ec2b6742c7a75cfb2a195e1e41bc5afe33d8b5aa015f616eac559ad9e6c9944
7
- data.tar.gz: 42591f0ed4cdc91895f154c7f3c50d5e572b9870c77604367207ab1567025a7fbb07c3d9ca90965f8e688188ed91d894ded759db07eabc5008c6c3da5642c118
6
+ metadata.gz: b5e47154cf50378f9960ddd1f782d3ec35c4c92395d3e74a0f734ad7f77c510c401ad26e46fa4aae96b30784e0263e407e93b6d58daf97070b9f2628a72b57ff
7
+ data.tar.gz: adec26a807cb648a9b6ad5d6cc3e6251f0b79eba52e1901f99cf102ef61db425bb6ea3e1676e51af1a5d9ab9a0b5aeda1e0c6f071ff48238e2fa103fae0b7d48
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .rubocop-https--*
data/.rubocop.yml CHANGED
@@ -1,6 +1,14 @@
1
1
  # This project follows the Ribose OSS style guide.
2
2
  # https://github.com/riboseinc/oss-guides
3
3
  # All project-specific additions and overrides should be specified in this file.
4
-
5
4
  inherit_from:
6
- - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
5
+ - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
6
+
7
+ # local repo-specific modifications
8
+
9
+ AllCops:
10
+ DisplayCopNames: false
11
+ StyleGuideCopsOnly: false
12
+ TargetRubyVersion: 2.4
13
+ Rails:
14
+ Enabled: true
@@ -1,3 +1,4 @@
1
1
  require_relative "utils/version"
2
2
  require_relative "utils/main"
3
+ require_relative "utils/image"
3
4
  require_relative "utils/log"
@@ -0,0 +1,177 @@
1
+ require "asciidoctor"
2
+ require "tempfile"
3
+ require "marcel"
4
+ require "mime/types"
5
+ require "base64"
6
+
7
+ module Metanorma
8
+ module Utils
9
+ class << self
10
+ class Namespace
11
+ def initialize(xmldoc)
12
+ @namespace = xmldoc.root.namespace
13
+ end
14
+
15
+ def ns(path)
16
+ return path if @namespace.nil?
17
+
18
+ path.gsub(%r{/([a-zA-z])}, "/xmlns:\\1")
19
+ .gsub(%r{::([a-zA-z])}, "::xmlns:\\1")
20
+ .gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1")
21
+ .gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
22
+ end
23
+ end
24
+
25
+ def save_dataimage(uri)
26
+ %r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
27
+ imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
28
+ imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
29
+ Tempfile.open(["image", ".#{imgtype}"]) do |f|
30
+ f.binmode
31
+ f.write(Base64.strict_decode64(imgdata))
32
+ f.path
33
+ end
34
+ end
35
+
36
+ SVG_NS = "http://www.w3.org/2000/svg".freeze
37
+
38
+ def svgmap_rewrite(xmldoc, localdirectory = "")
39
+ n = Namespace.new(xmldoc)
40
+ xmldoc.xpath(n.ns("//svgmap")).each_with_index do |s, i|
41
+ next unless svgmap_rewrite0(s, n, localdirectory, i)
42
+ next if s.at(n.ns("./target/eref"))
43
+
44
+ s.replace(s.at(n.ns("./figure")))
45
+ end
46
+ end
47
+
48
+ def svgmap_rewrite0(svgmap, namespace, localdirectory, idx)
49
+ if (i = svgmap.at(namespace.ns(".//image"))) && (src = i["src"])
50
+ path = svgmap_rewrite0_path(src, localdirectory)
51
+ File.file?(path) or return false
52
+ svg = Nokogiri::XML(File.read(path, encoding: "utf-8"))
53
+ i.replace(svgmap_rewrite1(svgmap, svg.root, namespace, idx))
54
+ /^data:/.match(src) and i["src"] = datauri(path)
55
+ elsif i = svgmap.at(".//m:svg", "m" => SVG_NS)
56
+ i.replace(svgmap_rewrite1(svgmap, i, namespace, idx))
57
+ else
58
+ return false
59
+ end
60
+ true
61
+ end
62
+
63
+ def svgmap_rewrite0_path(src, localdirectory)
64
+ if /^data:/.match?(src)
65
+ save_dataimage(src)
66
+ else
67
+ File.file?(src) ? src : localdirectory + src
68
+ end
69
+ end
70
+
71
+ def svgmap_rewrite1(svgmap, svg, namespace, idx)
72
+ svg_update_href(svgmap, svg, namespace)
73
+ svg_update_ids(svg, idx)
74
+ svg.xpath("processing-instruction()|.//processing-instruction()").remove
75
+ svg.to_xml
76
+ end
77
+
78
+ def svg_update_href(svgmap, svg, namespace)
79
+ targ = svgmap_rewrite1_targets(svgmap, namespace)
80
+ svg.xpath(".//m:a", "m" => SVG_NS).each do |a|
81
+ ["xlink:href", "href"].each do |p|
82
+ a[p] and x = targ[File.expand_path(a[p])] and a[p] = x
83
+ end
84
+ end
85
+ end
86
+
87
+ def svgmap_rewrite1_targets(svgmap, namespace)
88
+ svgmap.xpath(namespace.ns("./target"))
89
+ .each_with_object({}) do |t, m|
90
+ x = t.at(namespace.ns("./xref")) and
91
+ m[File.expand_path(t["href"])] = "##{x['target']}"
92
+ x = t.at(namespace.ns("./link")) and
93
+ m[File.expand_path(t["href"])] = x["target"]
94
+ t.remove if t.at(namespace.ns("./xref | ./link"))
95
+ end
96
+ end
97
+
98
+ def svg_update_ids(svg, idx)
99
+ ids = svg.xpath("./@id | .//@id")
100
+ .each_with_object([]) { |i, m| m << i.value }
101
+ return if ids.empty?
102
+
103
+ svg_update_ids_attrs(svg, ids, idx)
104
+ svg_update_ids_css(svg, ids, idx)
105
+ end
106
+
107
+ def svg_update_ids_attrs(svg, ids, idx)
108
+ svg.xpath(". | .//*[@*]").each do |a|
109
+ a.attribute_nodes.each do |x|
110
+ ids.include?(x.value) and x.value += sprintf("_%09d", idx)
111
+ end
112
+ end
113
+ end
114
+
115
+ def svg_update_ids_css(svg, ids, idx)
116
+ svg.xpath("//m:style", "m" => SVG_NS).each do |s|
117
+ c = s.children.to_xml
118
+ ids.each do |i|
119
+ c = c.gsub(%r[##{i}\b], sprintf("#%s_%09d", i, idx))
120
+ .gsub(%r(\[id\s*=\s*['"]?#{i}['"]?\]), sprintf("[id='%s_%09d']", i, idx))
121
+ end
122
+ s.children = c
123
+ end
124
+ end
125
+
126
+ # sources/plantuml/plantuml20200524-90467-1iqek5i.png
127
+ # already includes localdir
128
+ def datauri(uri, localdirectory = ".")
129
+ return uri if /^data:/.match?(uri)
130
+
131
+ path = datauri_path(uri, localdirectory)
132
+ return path unless File.exist?(path)
133
+
134
+ types = MIME::Types.type_for(path)
135
+ type = types ? types.first.to_s : 'text/plain; charset="utf-8"'
136
+ bin = File.open(path, "rb", &:read)
137
+ data = Base64.strict_encode64(bin)
138
+ "data:#{type};base64,#{data}"
139
+ end
140
+
141
+ def datauri_path(uri, localdirectory)
142
+ path = if %r{^([A-Z]:)?/}.match?(uri) then uri
143
+ else
144
+ File.exist?(uri) ? uri : File.join(localdirectory, uri)
145
+ end
146
+ unless File.exist?(path)
147
+ warn "image at #{path} not found"
148
+ return uri
149
+ end
150
+ path
151
+ end
152
+
153
+ def datauri2mime(uri)
154
+ %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
155
+ type = nil
156
+ imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
157
+ ::Tempfile.open(["imageuri", ".#{imgtype}"]) do |file|
158
+ type = datauri2mime1(file, imgdata)
159
+ end
160
+ [type]
161
+ end
162
+
163
+ def datauri2mime1(file, imgdata)
164
+ type = nil
165
+ begin
166
+ file.binmode
167
+ file.write(Base64.strict_decode64(imgdata))
168
+ file.rewind
169
+ type = Marcel::MimeType.for file
170
+ ensure
171
+ file.close!
172
+ end
173
+ type
174
+ end
175
+ end
176
+ end
177
+ end
data/lib/utils/log.rb CHANGED
@@ -7,48 +7,51 @@ module Metanorma
7
7
 
8
8
  def add(category, loc, msg)
9
9
  return if @novalid
10
+
10
11
  @log[category] = [] unless @log[category]
11
12
  @log[category] << { location: current_location(loc), message: msg,
12
13
  context: context(loc) }
13
14
  loc = loc.nil? ? "" : "(#{current_location(loc)}): "
14
- warn "#{category}: #{loc}#{msg}"
15
+ warn "#{category}: #{loc}#{msg}"
15
16
  end
16
17
 
17
- def current_location(n)
18
- return "" if n.nil?
19
- return n if n.is_a? String
20
- return "Asciidoctor Line #{"%06d" % n.lineno}" if n.respond_to?(:lineno) &&
21
- !n.lineno.nil? && !n.lineno.empty?
22
- return "XML Line #{"%06d" % n.line}" if n.respond_to?(:line) &&
23
- !n.line.nil?
24
- return "ID #{n.id}" if n.respond_to?(:id) && !n.id.nil?
25
- while !n.nil? &&
26
- (!n.respond_to?(:level) || n.level.positive?) &&
27
- (!n.respond_to?(:context) || n.context != :section)
28
- n = n.parent
29
- return "Section: #{n.title}" if n&.respond_to?(:context) &&
30
- n&.context == :section
18
+ def current_location(node)
19
+ if node.nil? then ""
20
+ elsif node.is_a? String then node
21
+ elsif node.respond_to?(:lineno) && !node.lineno.nil? &&
22
+ !node.lineno.empty?
23
+ "Asciidoctor Line #{'%06d' % node.lineno}"
24
+ elsif node.respond_to?(:line) && !node.line.nil?
25
+ "XML Line #{'%06d' % node.line}"
26
+ elsif node.respond_to?(:id) && !node.id.nil? then "ID #{node.id}"
27
+ else
28
+ while !node.nil? &&
29
+ (!node.respond_to?(:level) || node.level.positive?) &&
30
+ (!node.respond_to?(:context) || node.context != :section)
31
+ node = node.parent
32
+ return "Section: #{node.title}" if node&.respond_to?(:context) &&
33
+ node&.context == :section
34
+ end
35
+ "??"
31
36
  end
32
- "??"
33
37
  end
34
38
 
35
- def context(n)
36
- return nil if n.is_a? String
37
- n.respond_to?(:to_xml) and return n.to_xml
38
- n.respond_to?(:to_s) and return n.to_s
39
+ def context(node)
40
+ return nil if node.is_a? String
41
+
42
+ node.respond_to?(:to_xml) and return node.to_xml
43
+ node.respond_to?(:to_s) and return node.to_s
39
44
  nil
40
45
  end
41
46
 
42
47
  def write(file)
43
48
  File.open(file, "w:UTF-8") do |f|
44
49
  f.puts "#{file} errors"
45
- @log.keys.each do |key|
50
+ @log.each_key do |key|
46
51
  f.puts "\n\n== #{key}\n\n"
47
- @log[key].sort do |a, b|
48
- a[:location] <=> b[:location]
49
- end.each do |n|
52
+ @log[key].sort_by { |a| a[:location] }.each do |n|
50
53
  loc = n[:location] ? "(#{n[:location]}): " : ""
51
- f.puts "#{loc}#{n[:message]}"
54
+ f.puts "#{loc}#{n[:message]}"
52
55
  n[:context]&.split(/\n/)&.first(5)&.each { |l| f.puts "\t#{l}" }
53
56
  end
54
57
  end
data/lib/utils/main.rb CHANGED
@@ -2,56 +2,61 @@ require "asciidoctor"
2
2
  require "tempfile"
3
3
  require "sterile"
4
4
  require "uuidtools"
5
- require "mimemagic"
6
- require "mime/types"
7
- require "base64"
8
5
 
9
6
  module Metanorma
10
7
  module Utils
11
- NAMECHAR = "\u0000-\u0022\u0024\u002c\u002f\u003a-\u0040\\u005b-\u005e"\
12
- "\u0060\u007b-\u00b6\u00b8-\u00bf\u00d7\u00f7\u037e\u2000-\u200b"\
13
- "\u200e-\u203e\u2041-\u206f\u2190-\u2bff\u2ff0-\u3000".freeze
14
- #"\ud800-\uf8ff\ufdd0-\ufdef\ufffe-\uffff".freeze
15
- NAMESTARTCHAR = "\\u002d\u002e\u0030-\u0039\u00b7\u0300-\u036f"\
16
- "\u203f-\u2040".freeze
8
+ NAMECHAR = "\u0000-\u0022\u0024\u002c\u002f\u003a-\u0040\\u005b-\u005e"\
9
+ "\u0060\u007b-\u00b6\u00b8-\u00bf\u00d7\u00f7\u037e\u2000-\u200b"\
10
+ "\u200e-\u203e\u2041-\u206f\u2190-\u2bff\u2ff0-\u3000".freeze
11
+ NAMESTARTCHAR = "\\u002d\u002e\u0030-\u0039\u00b7\u0300-\u036f"\
12
+ "\u203f-\u2040".freeze
17
13
 
18
14
  class << self
19
- def to_ncname(s)
20
- start = s[0]
21
- ret1 = %r([#{NAMECHAR}#]).match(start) ? "_" :
22
- (%r([#{NAMESTARTCHAR}#]).match(start) ? "_#{start}" : start)
23
- ret2 = s[1..-1] || ""
24
- ret = (ret1 || "") + ret2.gsub(%r([#{NAMECHAR}#]), "_")
25
- ret
15
+ def to_ncname(tag)
16
+ start = tag[0]
17
+ ret1 = if %r([#{NAMECHAR}#]).match?(start)
18
+ "_"
19
+ else
20
+ (%r([#{NAMESTARTCHAR}#]).match?(start) ? "_#{start}" : start)
21
+ end
22
+ ret2 = tag[1..-1] || ""
23
+ (ret1 || "") + ret2.gsub(%r([#{NAMECHAR}#]), "_")
26
24
  end
27
25
 
28
26
  def anchor_or_uuid(node = nil)
29
27
  uuid = UUIDTools::UUID.random_create
30
- node.nil? || node.id.nil? || node.id.empty? ? "_" + uuid : node.id
28
+ node.nil? || node.id.nil? || node.id.empty? ? "_#{uuid}" : node.id
31
29
  end
32
30
 
33
- def asciidoc_sub(x)
34
- return nil if x.nil?
35
- return "" if x.empty?
36
- d = Asciidoctor::Document.new(x.lines.entries, { header_footer: false, backend: :html })
31
+ def asciidoc_sub(text, flavour = :standoc)
32
+ return nil if text.nil?
33
+ return "" if text.empty?
34
+
35
+ d = Asciidoctor::Document.new(
36
+ text.lines.entries,
37
+ { header_footer: false, backend: flavour }
38
+ )
37
39
  b = d.parse.blocks.first
38
40
  b.apply_subs(b.source)
39
41
  end
40
42
 
41
43
  def localdir(node)
42
44
  docfile = node.attr("docfile")
43
- docfile.nil? ? './' : Pathname.new(docfile).parent.to_s + '/'
45
+ docfile.nil? ? "./" : "#{Pathname.new(docfile).parent}/"
44
46
  end
45
47
 
46
48
  # TODO needs internationalisation
47
- def smartformat(n)
48
- n.gsub(/ --? /, "&#8201;&#8212;&#8201;").
49
- gsub(/--/, "&#8212;").smart_format.gsub(/</, "&lt;").gsub(/>/, "&gt;")
49
+ def smartformat(text)
50
+ text.gsub(/ --? /, "&#8201;&#8212;&#8201;")
51
+ .gsub(/--/, "&#8212;").smart_format.gsub(/</, "&lt;")
52
+ .gsub(/>/, "&gt;")
50
53
  end
51
54
 
52
55
  def endash_date(elem)
53
56
  elem.traverse do |n|
54
- n.text? and n.replace(n.text.gsub(/\s+--?\s+/, "&#8211;").gsub(/--/, "&#8211;"))
57
+ next unless n.text?
58
+
59
+ n.replace(n.text.gsub(/\s+--?\s+/, "&#8211;").gsub(/--/, "&#8211;"))
55
60
  end
56
61
  end
57
62
 
@@ -60,95 +65,34 @@ module Metanorma
60
65
  def set_nested_value(hash, keys, new_val)
61
66
  key = keys[0]
62
67
  if keys.length == 1
63
- hash[key] = hash[key].is_a?(Array) ? (hash[key] << new_val) :
64
- hash[key].nil? ? new_val : [hash[key], new_val]
68
+ hash[key] = if hash[key].is_a?(Array)
69
+ (hash[key] << new_val)
70
+ else
71
+ hash[key].nil? ? new_val : [hash[key], new_val]
72
+ end
73
+ elsif hash[key].is_a?(Array)
74
+ hash[key][-1] = {} if !hash[key].empty? && hash[key][-1].nil?
75
+ hash[key] << {} if hash[key].empty? || !hash[key][-1].is_a?(Hash)
76
+ set_nested_value(hash[key][-1], keys[1..-1], new_val)
77
+ elsif hash[key].nil? || hash[key].empty?
78
+ hash[key] = {}
79
+ set_nested_value(hash[key], keys[1..-1], new_val)
80
+ elsif hash[key].is_a?(Hash) && !hash[key][keys[1]]
81
+ set_nested_value(hash[key], keys[1..-1], new_val)
82
+ elsif !hash[key][keys[1]]
83
+ hash[key] = [hash[key], {}]
84
+ set_nested_value(hash[key][-1], keys[1..-1], new_val)
65
85
  else
66
- if hash[key].is_a?(Array)
67
- hash[key][-1] = {} if !hash[key].empty? && hash[key][-1].nil?
68
- hash[key] << {} if hash[key].empty? || !hash[key][-1].is_a?(Hash)
69
- set_nested_value(hash[key][-1], keys[1..-1], new_val)
70
- elsif hash[key].nil? || hash[key].empty?
71
- hash[key] = {}
72
- set_nested_value(hash[key], keys[1..-1], new_val)
73
- elsif hash[key].is_a?(Hash) && !hash[key][keys[1]]
74
- set_nested_value(hash[key], keys[1..-1], new_val)
75
- elsif !hash[key][keys[1]]
76
- hash[key] = [hash[key], {}]
77
- set_nested_value(hash[key][-1], keys[1..-1], new_val)
78
- else
79
- set_nested_value(hash[key], keys[1..-1], new_val)
80
- end
86
+ set_nested_value(hash[key], keys[1..-1], new_val)
81
87
  end
82
88
  hash
83
89
  end
84
90
 
85
- class Namespace
86
- def initialize(xmldoc)
87
- @namespace = xmldoc.root.namespace
88
- end
89
-
90
- def ns(path)
91
- return path if @namespace.nil?
92
- path.gsub(%r{/([a-zA-z])}, "/xmlns:\\1").
93
- gsub(%r{::([a-zA-z])}, "::xmlns:\\1").
94
- gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]* ?=)}, "[xmlns:\\1").
95
- gsub(%r{\[([a-zA-z][a-z0-9A-Z@/]*\])}, "[xmlns:\\1")
96
- end
97
- end
98
-
99
- def save_dataimage(uri)
100
- %r{^data:(image|application)/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
101
- imgtype.sub!(/\+[a-z0-9]+$/, '') # svg+xml
102
- imgtype = 'png' unless /^[a-z0-9]+$/.match imgtype
103
- Tempfile.open(['image', ".#{imgtype}"]) do |f|
104
- f.binmode
105
- f.write(Base64.strict_decode64(imgdata))
106
- f.path
107
- end
108
- end
109
-
110
- SVG_NS = "http://www.w3.org/2000/svg".freeze
111
-
112
- def svgmap_rewrite(xmldoc, localdirectory = "")
113
- n = Namespace.new(xmldoc)
114
- xmldoc.xpath(n.ns("//svgmap")).each do |s|
115
- next unless svgmap_rewrite0(s, n, localdirectory)
116
- next if s.at(n.ns("./target/eref"))
117
- s.replace(s.at(n.ns("./figure")))
118
- end
119
- end
120
-
121
- def svgmap_rewrite0(s, n, localdirectory)
122
- if i = s.at(n.ns(".//image")) and src = i["src"]
123
- path = /^data:/.match(src) ? save_dataimage(src) : File.file?(src) ? src : localdirectory + src
124
- File.file?(path) or return false
125
- svgmap_rewrite1(s, Nokogiri::XML(File.read(path, encoding: "utf-8")), path, n)
126
- /^data:/.match(src) and i["src"] = datauri(path)
127
- elsif i = s.at(".//m:svg", "m" => SVG_NS)
128
- svgmap_rewrite1(s, i, nil, n)
129
- else
130
- return false
131
- end
132
- true
133
- end
134
-
135
- def svgmap_rewrite1(s, svg, path, n)
136
- targets = s.xpath(n.ns("./target")).each_with_object({}) do |t, m|
137
- x = t.at(n.ns("./xref")) and m[File.expand_path(t["href"])] = "##{x['target']}"
138
- x = t.at(n.ns("./link")) and m[File.expand_path(t["href"])] = x['target']
139
- t.remove if t.at(n.ns("./xref | ./link"))
140
- end
141
- svg.xpath(".//m:a", "m" => SVG_NS).each do |a|
142
- a["xlink:href"] and x = targets[File.expand_path(a["xlink:href"])] and a["xlink:href"] = x
143
- a["href"] and x = targets[File.expand_path(a["href"])] and a["href"] = x
144
- end
145
- path and File.open(path, "w", encoding: "utf-8") { |f| f.write(svg.to_xml) }
146
- end
147
-
148
91
  # not currently used
149
92
  def flatten_rawtext_lines(node, result)
150
93
  node.lines.each do |x|
151
- if node.respond_to?(:context) && (node.context == :literal || node.context == :listing)
94
+ if node.respond_to?(:context) &&
95
+ (node.context == :literal || node.context == :listing)
152
96
  result << x.gsub(/</, "&lt;").gsub(/>/, "&gt;")
153
97
  else
154
98
  # strip not only HTML <tag>, and Asciidoc xrefs <<xref>>
@@ -174,45 +118,6 @@ module Metanorma
174
118
  end
175
119
  result.reject(&:empty?)
176
120
  end
177
-
178
- # sources/plantuml/plantuml20200524-90467-1iqek5i.png already includes localdir
179
- def datauri(uri, localdirectory = ".")
180
- return uri if /^data:/.match(uri)
181
- path = %r{^([A-Z]:)?/}.match?(uri) ? uri :
182
- File.exist?(uri) ? uri : File.join(localdirectory, uri)
183
- unless File.exist?(path)
184
- warn "image at #{path} not found"
185
- return uri
186
- end
187
- types = MIME::Types.type_for(path)
188
- type = types ? types.first.to_s : 'text/plain; charset="utf-8"'
189
- bin = File.open(path, 'rb', &:read)
190
- data = Base64.strict_encode64(bin)
191
- "data:#{type};base64,#{data}"
192
- end
193
-
194
- def datauri2mime(uri)
195
- %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
196
- type = nil
197
- imgtype = "png" unless /^[a-z0-9]+$/.match imgtype
198
- ::Tempfile.open(["imageuri", ".#{imgtype}"]) do |file|
199
- type = datauri2mime1(file, imgdata)
200
- end
201
- [type]
202
- end
203
-
204
- def datauri2mime1(file, imgdata)
205
- type = nil
206
- begin
207
- file.binmode
208
- file.write(Base64.strict_decode64(imgdata))
209
- file.rewind
210
- type = MimeMagic.by_magic(file)
211
- ensure
212
- file.close!
213
- end
214
- type
215
- end
216
121
  end
217
122
  end
218
123
  end