Class | Webgen::Tag::TikZ |
In: |
lib/webgen/tag/tikz.rb
|
Parent: | Object |
This tag allows the creation and inclusion of complex graphics using the PGF/TikZ library of LaTeX. You will need a current LaTeX distribution and the convert utility from ImageMagick.
LATEX_TEMPLATE | = | <<EOF \\nonstopmode \\documentclass{article} \\usepackage{tikz} \\pagestyle{empty} <% if param('tag.tikz.libraries') %> \\usetikzlibrary{<%= param('tag.tikz.libraries').join(',') %>} <% end %> \\begin{document} <% if param('tag.tikz.opts') %> \\begin{tikzpicture}[<%= param('tag.tikz.opts') %>] <% else %> \\begin{tikzpicture} <% end %> <%= body %> \\end{tikzpicture} \\end{document} EOF |
Create a graphic from the commands in the body of the tag.
# File lib/webgen/tag/tikz.rb, line 34 34: def call(tag, body, context) 35: path = param('tag.tikz.path') 36: path = Webgen::Path.make_absolute(context.ref_node.parent.alcn, path) 37: 38: mem_handler = website.cache.instance('Webgen::SourceHandler::Memory') 39: src_path = context.ref_node.node_info[:src] 40: parent = website.blackboard.invoke(:create_directories, context.ref_node.tree.root, File.dirname(path), src_path) 41: params = @params 42: 43: node = website.blackboard.invoke(:create_nodes, Webgen::Path.new(path, src_path), mem_handler) do |node_path| 44: mem_handler.create_node(node_path, context.ref_node.alcn) do |pic_node| 45: set_params(params) 46: document = ERB.new(LATEX_TEMPLATE).result(binding) 47: pic_path = compile(document, File.extname(path), context) 48: set_params(nil) 49: if pic_path 50: io = Webgen::Path::SourceIO.new { File.open(pic_path, 'rb') } 51: else 52: pic_node.flag(:dirty) 53: nil 54: end 55: end 56: end.first 57: attrs = {'alt' => ''}.merge(param('tag.tikz.img_attr')).collect {|name,value| "#{name.to_s}=\"#{value}\"" }.sort.unshift('').join(' ') 58: "<img src=\"#{context.dest_node.route_to(node)}\"#{attrs} />" 59: end
Compile the LaTeX document and convert the resulting PDF to the correct output image format specified by ext (the extension needs to include the dot).
# File lib/webgen/tag/tikz.rb, line 67 67: def compile(document, ext, context) 68: file = Tempfile.new('webgen-tikz') 69: file.write(document) 70: file.close 71: 72: FileUtils.mv(file.path, file.path + '.tex') 73: cmd_prefix = "cd #{File.dirname(file.path)}; " 74: output = `#{cmd_prefix} pdflatex --shell-escape -interaction=batchmode #{File.basename(file.path)}.tex` 75: if $?.exitstatus != 0 76: errors = output.scan(/^!(.*\n.*)/).join("\n") 77: raise Webgen::RenderError.new("Error while creating a TikZ picture: #{errors}", 78: self.class.name, context.dest_node, context.ref_node) 79: else 80: cmd = cmd_prefix + "pdfcrop #{File.basename(file.path)}.pdf #{File.basename(file.path)}.pdf; " 81: return unless run_command(cmd, context) 82: 83: render_res, output_res = param('tag.tikz.resolution').split(' ') 84: if param('tag.tikz.transparent') && ext =~ /\.png/i 85: cmd = cmd_prefix + 86: "gs -dSAFER -dBATCH -dNOPAUSE -r#{render_res} -sDEVICE=pngalpha -dGraphicsAlphaBits=4 -dTextAlphaBits=4 " + 87: "-sOutputFile=#{File.basename(file.path)}#{ext} #{File.basename(file.path)}.pdf" 88: else 89: cmd = cmd_prefix + "convert -density #{render_res} #{File.basename(file.path)}.pdf #{File.basename(file.path)}#{ext}" 90: end 91: return unless run_command(cmd, context) 92: 93: if render_res != output_res 94: cmd = cmd_prefix + "identify #{File.basename(file.path)}#{ext}" 95: return unless (output = run_command(cmd, context)) 96: width, height = output.scan(/\s\d+x\d+\s/).first.strip.split('x').collect {|s| s.to_f * output_res.to_f / render_res.to_f } 97: cmd = cmd_prefix + "convert -resize #{width}x#{height} #{File.basename(file.path)}#{ext} #{File.basename(file.path)}#{ext}" 98: return unless run_command(cmd, context) 99: end 100: file.path + ext 101: end 102: end
Runs the command cmd and returns it‘s output if successful or nil otherwise.
# File lib/webgen/tag/tikz.rb, line 105 105: def run_command(cmd, context) 106: output = `#{cmd}` 107: if $?.exitstatus != 0 108: raise Webgen::RenderError.new("Error while running a command for a TikZ picture: #{output}", 109: self.class.name, context.dest_node, context.ref_node) 110: else 111: output 112: end 113: end