lib/mathematical/render.rb in mathematical-0.0.1 vs lib/mathematical/render.rb in mathematical-0.0.2

- old
+ new

@@ -1,101 +1,75 @@ -require 'rbconfig' require 'fileutils' -require 'tmpdir' -require 'shellwords' require 'base64' +require 'tempfile' module Mathematical class Render DEFAULT_OPTS = { - :html_png_resolution => 200 + :ppi => 72.0, + :zoom => 1.0 } def initialize(opts = {}) - @os ||= ( - host_os = RbConfig::CONFIG['host_os'] - case host_os - when /darwin|mac os/ - "macosx" - when /linux/ - "linux" - else - raise Error, "unknown os: #{host_os.inspect}" - end - ) + raise(TypeError, "opts must be a hash!") unless opts.is_a? Hash - opts = DEFAULT_OPTS.merge(opts) - @temp_dir = Dir.mktmpdir - @args = [ - '--png', - '--use-preview-package', - # '--shell-dvipng', - # "'dvipng -D #{Shellwords.shellescape opts[:html_png_resolution].to_s}'", - ] + @config = DEFAULT_OPTS.merge(opts) + begin + @processer = Mathematical::Process.new(@config) + rescue TypeError => e # some error in the C code + raise + end + end + def render(text) + raise(TypeError, "text must be a string!") unless text.is_a? String - def render(contents) - in_tmpdir do |tmpdir| - @args << "--temp-directory #{Shellwords.shellescape tmpdir.first}" - @args << "--png-directory #{Shellwords.shellescape tmpdir.first}" + # TODO: figure out how to write svgs without the tempfile + tempfile = Tempfile.new('foo') + text.gsub(Mathematical::Parser::REGEX) do |maths| + if maths =~ /^\$(?!\$)/ + just_maths = maths[1..-2] + type = :inline + elsif maths =~ /^\\\((?!\\\[)/ + just_maths = maths[2..-4] + type = :inline + elsif maths =~ /^\\\[(?!\\\[)/ + just_maths = maths[2..-4] + type = :display + elsif maths =~ /^\\begin(?!\\begin)/ + just_maths = maths[16..-15] + type = :display + end - contents.gsub(Mathematical::Parser::REGEX) do |maths| - if maths =~ /^\$(?!\$)/ - maths = maths[1..-2] - type = :inline - else - type = :display - end + # this is the format itex2MML expects + if type == :inline + just_maths = "$#{just_maths}$" + else + just_maths = "$$#{just_maths}$$" + end - data = run_blahtex(maths, type) - if filename = data.match("<md5>(.+?)</md5>")[1] - "<img class=\"#{type.to_s}-math\" src=\"data:image/png;base64,#{png_to_base64(File.join(tmpdir, "#{filename}.png"))}\"/>" - end + begin + status = @processer.process(just_maths, tempfile.path) + raise RuntimeError unless status == 0 + svg_content = File.open(tempfile.path, 'r') { |image_file| image_file.read } + svg_content = svg_content.lines.to_a[1..-1].join + rescue RuntimeError => e # an error in the C code, probably a bad TeX parse + $stderr.puts e.message + return just_maths end - end - end - def run_blahtex(tex, type) - raise CommandNotFoundError, "Required commands missing: #{missing_commands.join(', ')} in PATH. (#{ENV['PATH']})" unless missing_commands.empty? - @args << '--displaymath' if type == :equation - - IO.popen(["bin/blahtex/#{@os}/blahtex", *@args].join(' '), 'w+') do |blahtex| - blahtex.write tex - blahtex.close_write - - output = blahtex.read - blahtex.close_read - - raise "Error running blahtex" unless $?.success? - - output + "<img class=\"#{named_type(type)}\" data-math-type=\"#{named_type(type)}\" src=\"data:image/svg+xml;base64,#{svg_to_base64(svg_content)}\"/>" end + tempfile.close + tempfile.unlink end - def png_to_base64(path) - File.open(path, 'r') { |image_file| Base64.encode64(image_file.read).gsub(/\n/, '') } + def svg_to_base64(contents) + Base64.strict_encode64(contents) end -private - - # Check toolchain availability and returns array of missing tools - def missing_commands - commands = [] - commands << "dvipng" unless can_run?("dvipng -v") - commands - end - - # Trial command and check if return code is zero - def can_run?(command) - `#{command} 2>&1` - $?.exitstatus.zero? - end - - def in_tmpdir - path = FileUtils.mkdir_p Dir.tmpdir - yield path - ensure - FileUtils.rm_rf( path ) + def named_type(type) + "#{type.to_s}-math" end end end