lib/utils/image.rb in metanorma-utils-1.4.0.1 vs lib/utils/image.rb in metanorma-utils-1.4.1
- old
+ new
@@ -1,9 +1,7 @@
-require "asciidoctor"
require "tempfile"
require "marcel"
-require "mime/types"
require "base64"
module Metanorma
module Utils
class << self
@@ -124,55 +122,74 @@
end
end
# sources/plantuml/plantuml20200524-90467-1iqek5i.png
# already includes localdir
- def datauri(uri, localdirectory = ".")
- return uri if /^data:/.match?(uri)
+ def datauri(uri, local_dir = ".")
+ # Return the data URI if it already is a data URI
+ return uri if datauri?(uri)
- path = datauri_path(uri, localdirectory)
- return path unless File.exist?(path)
+ # Return the URL if it is a URL
+ return uri if url?(uri)
- types = MIME::Types.type_for(path)
- type = types ? types.first.to_s : 'text/plain; charset="utf-8"'
- bin = File.open(path, "rb", &:read)
+ local_path = uri
+ relative_path = File.join(local_dir, uri)
+
+ # Check whether just the local path or the other specified relative path
+ # works.
+ path = [local_path, relative_path].detect do |p|
+ File.exist?(p) ? p : nil
+ end
+
+ unless path && File.exist?(path)
+ warn "Image specified at `#{uri}` does not exist."
+ # Return original provided location
+ return uri
+ end
+
+ encode_datauri(path)
+ end
+
+ def encode_datauri(path)
+ return nil unless File.exist?(path)
+
+ type = Marcel::MimeType.for(Pathname.new(path)) ||
+ 'text/plain; charset="utf-8"'
+
+ bin = File.binread(path)
data = Base64.strict_encode64(bin)
"data:#{type};base64,#{data}"
+ rescue StandardError
+ warn "Data-URI encoding of `#{path}` failed."
+ nil
end
- def datauri_path(uri, localdirectory)
- path = if %r{^([A-Z]:)?/}.match?(uri) then uri
- else
- File.exist?(uri) ? uri : File.join(localdirectory, uri)
- end
- unless File.exist?(path)
- warn "image at #{path} not found"
- return uri
- end
- path
+ def datauri?(uri)
+ /^data:/.match?(uri)
end
- def datauri2mime(uri)
- %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
- type = nil
- imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
- ::Tempfile.open(["imageuri", ".#{imgtype}"]) do |file|
- type = datauri2mime1(file, imgdata)
- end
- [type]
+ def url?(url)
+ %r{^([A-Z]:)?/}.match?(url)
end
- def datauri2mime1(file, imgdata)
- type = nil
- begin
- file.binmode
- file.write(Base64.strict_decode64(imgdata))
- file.rewind
- type = Marcel::MimeType.for file
- ensure
- file.close!
- end
- type
+ def decode_datauri(uri)
+ %r{^data:(?<mimetype>[^;]+);base64,(?<mimedata>.+)$} =~ uri
+ return nil unless mimetype && mimedata
+
+ data = Base64.strict_decode64(mimedata)
+ {
+ type_declared: mimetype,
+ type_detected: Marcel::MimeType.for(data, declared_type: mimetype),
+ data: data,
+ }
+ end
+
+ # FIXME: This method should ONLY return 1 type, remove Array wrapper
+ def datauri2mime(uri)
+ output = decode_datauri(uri)
+ return nil unless output && output[:type_detected]
+
+ [output[:type_detected]]
end
end
end
end