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