Skip to content

Instantly share code, notes, and snippets.

@MatteoRagni
Last active December 30, 2015 12:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MatteoRagni/c788528aa26feba6f9db to your computer and use it in GitHub Desktop.
Save MatteoRagni/c788528aa26feba6f9db to your computer and use it in GitHub Desktop.
Simple script to create equations that could be inserted in Github readme files as images.

generator.rb [OPTIONS]

Install

There are some dependencies needed:

  • ruby (2.*.*)
  • imagemagik (6.*.*.*)
  • latex-package
  • file (5.*)

All you need to do is to run the following command (use curl or wget or your preferred network downloader):

sudo curl "https://gist.githubusercontent.com/MatteoRagni/c788528aa26feba6f9db/raw/415f09dc102a7dc053040f16ba14e507dbb536e0/EquationCreator.rb" > /usr/local/bin/EquationCreator.rb"

Now you are able to run the script from command line.

Use

This script generates a series of image equations (gif) starting from a yaml file that contains a simple template (standalone). Also resizes image canvas if needed (to display all images at the same size), that means image border are enlarged, but image content is not rescaled. This is done to keep as simple as possible the use of final image on Github :octocat:.

-h, --help

show this help

-i, --input [yaml file]

input YAML file is required. File must contains:

  • template used to create latex final image (object $eq)
  • configuration (definitions to be inserted in preamble)
  • list of equations, that must contains:
    • name for equation
    • options (to be used in template, such as inline)
    • data (contained equation)

-o, --output [directory]

directory in which image files will be saved (if directory does not exists, will be created).

-r, --resize [px|max|MAX|]

size of the final image (width). The height will be collected automagically :) If "max", will use the maximum value of the images in output directory

Example

This is an example of yaml file:

---
configuration: |-
  \usepackage{varwidth}
  \usepackage{amsmath}
  \def \xx {\mathbf{x}}
  \def \activeset {\mathcal{A}}
  \def \real {\mathbb{R}}

template: |-
  \documentclass{standalone}
  <%= $eq["configuration"] %>
  \begin{document}
  \begin{varwidth}{\linewidth}
  <% if $eq["options"] =~ /nolabel/ %>$$<%= $eq["data"] %>$$<% else %>$$<%= $eq["data"] %>\hspace{3cm}(<%= $eq["label"] %>)$$<% end %>
  \end{varwidth}
  \end{document}

equations:

  - name: eq_problem
    options:
    data: |-
      \arraycolsep=1.4pt\def\arraystretch{2}
      \begin{array}{rcl}
      \xx & = & \mathrm{arg}~\underset{\xx}{\mathrm{min}} ~ \dfrac{1}{2} \xx^{T} M \xx + \mathbf{g}^{T}\xx + c \\
      \mathrm{subject~to} & & \mathbf{a}^{T}_{j} \xx + b_j = 0 \qquad j \in \left\{1 \dots m\right\} \\
       &  & \mathbf{a}^{T}_{j} \xx + b_j \geq 0  \qquad j \in \left\{m+1 \dots r\right\} \quad  m > r \\
      \end{array}

  - name: eq_activeset
    options:
    data: |-
      \activeset(\mathbf{z}) = \left\{ 1 \dots m \right\} \cup \left\{ j \in \left\{ m+1 \dots r \right\} ~|~ \mathbf{a}^{T}_{j} \mathbf{z} + b_j = 0  \right\}

Generates with the options:

EquationCreator.rb -i example.yaml -o . -r max

The two images:

eq_problem.gif

eq_activeset.gif

#!/usr/bin/env ruby
##
# Generates Equations GIF files for readme.
# Equations must be inserted in a YAML file.
# The parts in configuration will be inserted in each file, in header section,
# to allow definitions of new command and so on.
#
# Binary accepts as input:
#
# * `-i (--input)`: input equations file
# * `-o (--output)`: output equation directory, in which all svg will be saved
# * `-r (--resize)`: final width or "max" to mimic dimension of biggest image (height will be constant)
#
class EquationGenerator
def initialize(fn, out)
raise ArgumentError, "fn (input file name) must be a String. Received a #{fn.class}" unless fn.is_a? String
raise ArgumentError, "out (output directory name) must be a String. Received a #{out.class}" unless out.is_a? String
raise ArgumentError, "fn points to a file that does not exists." unless File.exist? fn
@config = {
dvilatex: "dvilualatex",
dvigif: "dvigif",
dvilatex_opt: "",
dvigif_opt: "-D 200 -bg Transparent",
convert: "convert",
convert_opts: ""
}
raise LoadError, "[#{@config[:dvilatex]}] not found. Is it installed?" if `which #{@config[:dvilatex]}` == ""
raise LoadError, "[#{@config[:dvigif]}] not found. Is it installed?" if `which #{@config[:dvigif]}` == ""
raise LoadError, "[#{@config[:convert]}] not found. Is it installed?" if `which #{@config[:convert]}` == ""
if not (require 'erb')
begin
ERB
rescue NameError
raise LoadError, "Cannot load gem ERB. PLease install it!"
end
end
if not (require 'yaml')
begin
YAML
rescue NameError
raise LoadError, "Cannot load YAML. Something is wrong..."
end
end
if not (require 'fileutils')
begin
FileUtils
rescue NameError
raise LoadError, "Cannot load FileUtils. Something is wrong..."
end
end
@file = fn
@output = out
load_data
check_dir
end
def run
Dir.chdir @output do
puts "[INFO] Starting Building Image"
@no_eqs = @data["equations"].size
@data["equations"].each_with_index do |eq, i|
puts " [#{i + 1} of #{@no_eqs}]\n - Reading... "
eq["label"] = i + 1
eq["name"] = eq["name"].gsub(/\s+/, "")
$eq = eq
$eq["configuration"] = @data["configuration"]
puts " - Elaborating template..."
file = File.new($eq["name"] + ".tex", "w+")
file.puts ERB.new(@data["template"]).result()
file.close
#binding.pry
puts " - Compiling latex source..."
lat_output = `#{@config[:dvilatex]} #{file.path} #{@config[:dvilatex_opt]}`
puts " - Creating image..."
img_output = `#{@config[:dvigif]} #{file.path.gsub("tex", "dvi")} #{@config[:dvigif_opt]}`
puts " - Copying file to output directory..."
FileUtils.mv file.path.gsub(".tex", "1.gif"), (eq["name"] + ".gif")
puts " - Removing intermediate files..."
FileUtils.rm file.path.gsub("tex", "dvi")
FileUtils.rm file.path.gsub("tex", "aux")
FileUtils.rm file.path.gsub("tex", "log")
FileUtils.rm file.path
#FileUtils.mv($eq["name"] + "1.gif", file.path.gsub("tex", "gif"), force: true)
puts " ...done"
end
puts "Completed!"
end
end
def resize(sz)
raise ArgumentError, "Size must be a String" unless sz.is_a? String
puts "Begin resizing"
Dir.chdir @output do
files = Dir["*.gif"]
sizes = []
files.each_with_index do |f, i|
str = `file #{f}`
if str =~ /([0-9]+)\sx\s([0-9]+)/
sizes[i] = [$1.to_i, $2.to_i]
end
end
if sz.upcase == "MAX"
maxsize = (sizes.max { |x,y| x[0] <=> y[0] })[0]
else
maxsize = sz.to_i
raise ArgumentError, "Size value is 0?? (maybe a conversion error?)" if sz == 0
end
files.each_with_index do |f,i|
print " Resizing: #{i+1} of #{files.size}... "
`convert #{f} -background none -compose Copy -gravity center -extent #{maxsize}x#{sizes[i][1]} #{f}`
puts "done"
end
puts "Completed!"
end
end
def load_data
@data = YAML::load_file(@file)
end
def check_dir
FileUtils.mkdir_p @output unless Dir.exist? @output
end
end
if __FILE__ == $0 then
require 'getoptlong'
opts = GetoptLong.new(
['--help', '-h', GetoptLong::NO_ARGUMENT],
['--input', '-i', GetoptLong::REQUIRED_ARGUMENT],
['--output', '-o', GetoptLong::REQUIRED_ARGUMENT],
['--resize', '-r', GetoptLong::REQUIRED_ARGUMENT]
)
input_file = nil
output_dir = nil
resize_size = nil
opts.each do |opt, arg|
case opt
when '--help'
puts <<-HELPTEXT
generator.rb [OPTIONS]
-h, --help
show this help
-i, --input [yaml file]
input YAML file is required. File must contains:
* template used to create latex final image (object $eq)
* configuration (definitions to be inserted in preamble)
* list of equations, that must contains:
* name for equation
* options (to be used in template, such as inline)
* data (contained equation)
-o, --output [directory]
directory in which image files will be saved (if directory does not exists,
will be created).
-r, --resize [px|max|MAX|]
size of the final image (width). The height will be collected automagically :)
If "max", will use the maximum value of the images in output directory
HELPTEXT
exit 0
when '--input'
input_file = arg
when '--output'
output_dir = arg.gsub(/\s/, "_").strip
when '--resize'
resize_size = arg
end
end
if not input_file
puts "Missing input file (--input, -i)"
exit 0
end
if not output_dir
puts "Missing output directory (--output, -o)"
exit 0
end
eq = EquationGenerator.new(input_file, output_dir)
eq.run
if resize_size
eq.resize resize_size
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment