metanorma / vectory

Convert between vector image formats (Ruby)
2 stars 0 forks source link

Create "vectory" gem #1

Closed ronaldtse closed 1 year ago

ronaldtse commented 1 year ago

As @opoudjis put it:

Vectory that shall give you a glorious vectory over EPS files

This gem performs vector-to-vector conversions (pairwise EPS/PS/EMF/SVG) and depends on libraries like emf2svg as well as tools like Inkscape whenever necessary.

ronaldtse commented 1 year ago

The code to extract is located here:

The conversions we need to support are:

Features

ronaldtse commented 1 year ago

@alexeymorozov would you have time for this? Thanks!

opoudjis commented 1 year ago

And note that data-uri processing code is already in https://github.com/metanorma/metanorma-utils/blob/main/lib/utils/image.rb . You may want to refer to it for the data-uri code, and move some of its svg map processing code into this gem.

ronaldtse commented 1 year ago

Good point, let's move all the Data URI code into Vectory too.

ronaldtse commented 1 year ago

I updated the gem descriptions too.

alexeymorozov commented 1 year ago

Started working on it.

alexeymorozov commented 1 year ago

Gonna wrap current code in an API like:

  1. emf to svg, from xml to content Vectory::Emf.from_xml(node).to_svg.content

  2. eps to svg, from xml to file Vectory::Eps.from_xml(node).to_svg.path

  3. svg to emf, from xml to file Vectory::Svg.from_xml(node).to_emf.path

ronaldtse commented 1 year ago

@alexeymorozov excellent API. However EMF and EPS both do not have XML forms, so the input to load EMF and EPS will have to come from either a memory blog or a file path.

When conversion happens, the file should either be held in memory or placed in a temporary folder.

e.g.

Vectory::Eps.from_path(eps_path).to_svg.content
# => Vectory::Svg

Vectory::Eps.from_path(eps_path).to_svg.content
# => content of SVG (in this case SVG is in XML)

Vectory::Eps.from_path(eps_path).to_svg.path
# The file has not been written
# => raise NotWrittenToDiskError

Vectory::Eps.from_path(eps_path).to_svg.write.path
# default writes to tmpdir
# => /tmp/xxx/yyy

Vectory::Eps.from_path(eps_path).to_svg.write(svg_destination_path).path
# => {svg_destination_path}
alexeymorozov commented 1 year ago

@ronaldtse Thanks for clarification! I researched a little deeper in isodoc's code and got up with the following API:

def from_datauri_to_content(uri)
  %r{^data:(?<imgclass>image|application)/(?<imgtype>[^;]+);(?:charset=[^;]+;)?base64,(?<imgdata>.+)$} =~ uri
  Base64.strict_decode64(imgdata)
end

# 1. emf to svg, from the image tag to content
datauri = img.at(ns("./emf/@src")).text
content = from_datauri_to_content(datauri)
Vectory::Emf.from_content(content).to_svg.content

# 2. eps to svg, from the image tag to file
datauri = if node.text.strip.empty?
            node["src"]
          else
            a = Base64.strict_encode64(node.children.to_xml)
            "data:application/postscript;base64,#{a}"
          end
content = from_datauri_to_content(datauri)
Vectory::Eps.from_content(content).to_svg.write.path

# 3. svg to emf, from the image tag to file
datauri = if node.elements&.first&.name == "svg"
            a = Base64.strict_encode64(node.children.to_xml)
            "data:image/svg+xml;base64,#{a}"
          else
            node["src"]
          end
content = from_datauri_to_content(datauri)
Vectory::Svg.from_content(content).to_emf.write.path

Vectory could support:

::from_path
::from_content
::from_datauri # to be consistent with output in a form of a datauri

Will reuse current code from isodoc in Vectory Ruby objects and pass the first PR to review.

ronaldtse commented 1 year ago

Yes that's correct. Thanks!

ronaldtse commented 1 year ago

@alexeymorozov any ETA on when it can be used? Thanks!

alexeymorozov commented 1 year ago

@ronaldtse I'm planning on finishing the file system operations in the beginning of the next week. After that it can be used.

After the file system operations I planned to work on:

  1. Add additional properties to the Image class: MIME type, size information, file path, height / width information, frame information
  2. Extract svgmap_rewrite (https://github.com/metanorma/metanorma-utils/blob/main/lib/utils/image.rb). I don't know much about it, may need to talk with someone to understand what this feature does and why it's better to move it to vectory.
ronaldtse commented 1 year ago

@alexeymorozov so there are two important operations of SVGs:

  1. SVGs can be embedded in XML and HTML as XML. This means that its ids and internal integrity can affect the document that embeds it. For example, if the HTML document contains an element with id called circle_box, and the SVG contains an element with id of circle_box, the HTML will fail validation because there are two conflicting ids.

  2. SVGs can contain <a> anchor links. Referential integrity of the links may or may not exist: an SVG hyperlink can point to an external link that is outside the SVG on the Internet, or it can also point to an element in the HTML/XML that embeds the SVG.

When embedding SVGs, we need to "namespace" the SVG IDs:

alexeymorozov commented 1 year ago

@ronaldtse Thank you for explanation! I will implement it, API can be:

Svg.from_path(path).rewrite("foobar-svg").content
ronaldtse commented 1 year ago

Thanks @alexeymorozov ! Can we move remaining issues out to individual tickets and close this one since it’s almost ready?

alexeymorozov commented 1 year ago

Of course! :) Extracted #17 and #18, closing this one.