Project

vectory

0.0
The project is in a healthy, maintained state
Vectory performs pairwise vector image conversions for common vector image formats, such as SVG, EMF, EPS and PS.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 3.2.0
~> 1.0
>= 0
~> 1.0
~> 1.14
 Project Readme

Vectory

Gem Version rake Pull Requests Commits since latest

Purpose

Vectory is a Ruby gem that performs pairwise vector image conversions for common vector image formats (EPS, PS, EMF, SVG).

Vectory shall give you a glorious vectory over EPS files.

Installation

Prerequisites

Vectory relies on the following software to be installed:

Note
Inkscape 1.3.1+ does not work properly with EPS/PS on Windows. To avoid this issue, the 1.3.0 version of Inkscape can be used.

Gem install

gem install vectory

Or include it in your gemspec.

Usage

$ vectory [-o {output-file-name}] -f {format} {input-file-name}

Where,

format

the desired output format (one of: svg, eps, ps, emf)

input-file-name

file path to the input file

output-file-name

file path to the desired output file (with the file extension) (default: writes to a current directory by the input filename with an extension changed to a desired format)

Using the Ruby library

Some examples:

Take EMF as a path to a file and return SVG as a string:

path = "path/to/file.emf"

Vectory::Emf.from_path(path).to_svg.content

Take EPS as a string and return EMF as a path to a file:

# NOTE: content is shortened for readability
content = "%!PS-Adobe-3.0 EPSF-3.0\n ... %%Trailer"

Vectory::Eps.from_content(content).to_emf.write.path

Take SVG as a datauri and return EMF as a datauri:

# NOTE: datauri is shortened for readability
uri = "data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0 ... GRkYiLz48L3N2Zz4="

Vectory::Datauri.new(uri).to_vector.to_emf.to_uri.content

What is supported?

There are several vector classes which support conversion between each other:

Vectory::Eps
Vectory::Ps
Vectory::Emf
Vectory::Svg

Each of them can be instantiated in several ways:

Vectory::Eps.from_path("images/img.eps")
Vectory::Eps.from_content("%!PS-Adobe-3.0...")
Vectory::Eps.from_datauri("data:image/svg+xml;base64,PHN2 ... 2Zz4=")
Vectory::Eps.from_node(Nokogiri::XML(
  "<image mimetype="application/postscript" alt="3">
    %!PS-Adobe-3.0 EPSF-3.0 ...
   </image>"
).child)

Converting to other formats:

Vectory::Eps.from_content(content).to_ps
Vectory::Eps.from_content(content).to_emf
Vectory::Eps.from_content(content).to_svg

Several ways of getting content of an object:

Vectory::Eps.from_content(content).to_svg.content
Vectory::Eps.from_content(content).to_svg.to_uri.content # as datauri
Vectory::Eps.from_content(content).to_svg.write.path

Datauri

Also there is the Vectory::Datauri class which represents vectory images in the datauri format.

Convert an SVG datauri to a plain SVG:

# NOTE: datauri is shortened for readability
uri = "data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0 ... GRkYiLz48L3N2Zz4="
Vectory::Datauri.new(uri).to_vector.content

Convert an EPS file to its datauri representation:

eps = Vectory::Eps.from_path("img.eps")
Vectory::Datauri.from_vector(eps).content

There is also a simplified API for this case:

Vectory::Eps.from_path("img.eps").to_uri.content

SVG mapping (for the metanorma project)

Vectory can integrate SVG files into XML or HTML, respecting internal id and link references. It supports ID disambiguation for multi-document and multi-svgmap scenarios.

Basic usage
xml_string = Vectory::SvgMapping.from_path("doc.xml").to_xml
ID suffixing for uniqueness

When processing multiple documents or multiple svgmaps within a document, SVG IDs must be unique to avoid conflicts. Vectory applies two types of suffixes:

ID suffix (Cross-document uniqueness)

An optional suffix derived from document or container identity (e.g., _ISO_17301-1_2016). This provides uniqueness across documents or collections.

Index suffix (Multi-svgmap uniqueness)

Automatically applied based on the svgmap’s position in the document (0, 1, 2, …​). Formatted as a 9-digit zero-padded number (e.g., _000000000, _000000001). This provides uniqueness when a document contains multiple svgmaps.

Final ID composition
Original ID:  fig1
With ID suffix only:  fig1_ISO_17301-1_2016
With both suffixes:   fig1_ISO_17301-1_2016_000000000
Usage with ID suffix
mapping = Vectory::SvgMapping.new(doc, "", id_suffix: "_ISO_17301-1_2016")
xml_string = mapping.call.to_xml
Input format

The input XML must support the svgmap tag with link mapping.

<svgmap id="_4072bdcb-5895-4821-b636-5795b96787cb">
  <figure><image src="action_schemaexpg1.svg"/></figure>
  <target href="mn://action_schema">
    <xref target="ref1">Computer</xref>
  </target>
  <target href="http://www.example.com">
    <link target="http://www.example.com">Phone</link>
  </target>
</svgmap>
action_schemaexpg1.svg
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <style type="text/css">
    #Layer_1 { fill:none }
    svg[id = 'Layer_1'] { fill:none }
    .st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
  </style>
  <a xlink:href="mn://action_schema" xlink:dummy="Layer_1">
    <rect x="123.28" y="273.93" class="st0" width="88.05" height="41.84"/>
  </a>
  <a xlink:href="mn://basic_attribute_schema" >
    <rect x="324.69" y="450.52" class="st0" width="132.62" height="40.75"/>
  </a>
  <a xlink:href="mn://support_resource_schema" >
    <rect x="324.69" y="528.36" class="st0" width="148.16" height="40.75"/>
  </a>
</svg>
Output format
<figure>
  <svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1'
       id='Layer_1_000000001' x='0px' y='0px' viewBox='0 0 595.28 841.89'>
    <style> #Layer_1_000000001 { fill:none }</style>
    <a xlink:href='#ref1' xlink:dummy='Layer_1_000000001'>
      <rect x='123.28' y='273.93' class='st0' width='88.05' height='41.84'/>
    </a>
    <a xlink:href='mn://basic_attribute_schema'>
      <rect x='324.69' y='450.52' class='st0' width='132.62' height='40.75'/>
    </a>
    <a xlink:href='mn://support_resource_schema'>
      <rect x='324.69' y='528.36' class='st0' width='148.16' height='40.75'/>
    </a>
  </svg>
</figure>
Inline SVG support

SVG can also be provided inline within the svgmap:

<svgmap id="_60dadf08-48d4-4164-845c-b4e293e00abd">
  <figure>
    <svg xmlns='http://www.w3.org/2000/svg' id='Layer_1'>
      <a href="mn://action_schema">
        <rect x="123.28" y="273.93" class="st0"/>
      </a>
    </svg>
  </figure>
  <target href="mn://action_schema">
    <xref target="ref1">Computer</xref>
  </target>
</svgmap>
Data URI support

Images can be provided as data URIs:

<svgmap id="_60dadf08-48d4-4164-845c-b4e293e00abd">
  <figure>
    <image src='data:image/svg+xml;base64,PD94...'/>
  </figure>
  <target href="href1.htm">
    <xref target="ref1">Computer</xref>
  </target>
</svgmap>

File system operations

An image object contains information where it is written. It can be obtained with the #path API:

vector = Vectory::Eps.from_path("img.eps")
vector.path

Before the first write it raises the NotWrittenToDiskError error:

vector.path # => raise NotWrittenToDiskError

After writing it returns a path of the image on a disk:

vector.write
vector.path # => "/tmp/xxx/yyy"

By default it writes to a temporary directory but it can be changed by providing an argument with a desired path:

vector.write("images/img.eps")
vector.path # => "images/img.eps"

Since an image can be initially read from a disk, it also keeps an initial path. To avoid accidental overwrite, this path is used only for read-only purposes.

vector.initial_path # => "storage/images/img.eps"

Additional properties

The following additional properties are supported:

Datauri#mime
Datauri#height
Datauri#width
Vector (Eps, Ps, Svg, Emf)
Vector#mime
Vector#size
Vector#file_size
Vector#height
Vector#width

Development

Regenerating test fixtures

Some test fixtures are generated by external tools (Ghostscript, Inkscape, cairo). When these tools are updated, the reference files may need to be regenerated.

To regenerate all test fixtures:

bundle exec rake regenerate_fixtures

This will update the following files:

  • spec/examples/ps2eps/ref.eps - PS to EPS conversion reference

  • spec/examples/ps2svg/ref.svg - PS to SVG conversion reference

  • spec/examples/svg/doc2-ref.xml - SVG mapping reference

Note
After regenerating fixtures, review the changes to ensure they are expected before committing.

Releasing

Releasing is done automatically with GitHub Actions. Just bump and tag with gem-release.

For a patch release (0.0.x) use:

gem bump --version patch --tag --push

For a minor release (0.x.0) use:

gem bump --version minor --tag --push

Contributing

Bug reports and pull requests are welcome on GitHub at: