Adding LaTeX to Notes with Ruby

I’ve finally come up with a some what novel use of ruby that is saving me a bunch of time at school, so now I’ll pass the savings on to you!

The Problem:

I want to take notes in class using my Mac. More specifically, I want to use OmniOutliner (though this method should be adaptable to any editor that can embed images). However, in more than a few computer science classes I’ve had, the mathematics get pretty heavy. And thus far summations, fractions, large equations, etc. don’t like to be typed out. They hate it. This has limited my ability to use my afore mentioned Mac as a note taking center for those classes.

So how can I still use OmniOutliner to take notes that include a large mathematical component?

The Solution:

In a word LaTeX. Let me explain.

Hopefully everyone’s familiar with LaTeX – a markup language used to format books, papers, etc. What its really good at is creating equations. The syntax is different, but not difficult, and it allows you to basically write out as complicated mathematical formula as you like in plain text. This gets converted to your actual equation using the TeX typesetting program.

I’d used LaTeX before a semester or so ago for writing up my homework for a particular class. For this, I’d installed the requisite packages via MacPorts and used the best editor of all time, TextMate, to write up the document and convert it to pdf.

But how do we add formatted LaTeX equations to a program like OmniOutliner, which doesn’t know how to parse LaTeX? Well, thats what this post is about.

conversion

More after the break.

Basic Idea:

Here’s the gist of my solution:

  • Type up the equation in LaTeX, inside of OmniOutliner.
  • Highlight the text version of your equation and hit a shortcut key sequence
  • Have a background process take your highlighted formula and convert it into an image of the LaTeX converted equation.
  • Insert this image back into the notes, replacing the original text one.

Easy, Breezy, Beautiful.

How I Did It:

I found a perl script that performed most of what I wanted to do. This thing takes a simple LaTeX file and creates a .gif out of it, meant to be used for websites.

So, I modified it a bit to suite my needs:

  • Translated the code into ruby, cause its cooler.
  • Change it to create .png files – cause I like them better.
  • Have it use copy and paste to get the equation and place the image into the program, instead of using an input file.

Here’s my version of the program:

#!/usr/bin/env ruby

# Note: if using the appscript gem, rubygems must be required first:
begin; require 'rubygems'; rescue LoadError; end

require "appscript"
require "osax"
include Appscript

#create new datetime for the file name
dt = DateTime.now

#Start with constants needed
 Dpi = 90;
 Res = 0.1;

 Background = ""
 Transparent = "ff/ff/ff"

 CmdGIF = 'ppmtogif' # <- shouldn't be used anywhere
 CmdGIFdecode = 'giftopnm' # &#91;:command_down&#93;)

copied_text = `pbpaste`# copied_text now has the section we want to convert

# --- Component that limits universal functionality
# ---- would want a method of getting the 'current' active applications open document path
# acquire the folder where the current notes file is stored
omni = app('OmniOutliner Professional')
#doc_name = omni.windows&#91;1&#93;.documents&#91;1&#93;.name.get
doc_path = omni.windows&#91;1&#93;.documents&#91;1&#93;.path.get
root_folder = File.dirname(doc_path)
#create a img folder in this directory if not already present
unless File.directory?(root_folder+'/img')
  system("mkdir #{root_folder}/img")
end

#switch to the img directory of the root folder
Dir.chdir(root_folder+'/img')

#function to handle the latex conversion stuff
def create_png(copied_text)
  # latex document with copied text
  doc = "\\documentclass&#91;12pt&#93;{article} \n \\pagestyle{empty} \n \\begin{document} \n \\begin{displaymath} \n" + copied_text + "\n \\end{displaymath}	\n \\end{document}"

  # create new file for this tex doc
  File.open("#{Name}.tex","w") {|io| io.puts doc}

  system("echo x | /opt/local/bin/latex "+Name+".tex");
  system("/opt/local/bin/dvips -f #{Name} > _temp_#{Name}.ps\n");

  #build command
  cmd = "echo quit | /opt/local/bin/gs -q -dNOPAUSE  -r" + (Dpi / Res).to_i.to_s + "x"+ (Dpi / Res).to_i.to_s +
  	" -sOutputFile=- -sDEVICE=pbmraw _temp_#{Name}.ps | " +
  	"/opt/local/bin/pnmcrop -white | /opt/local/bin/pnmdepth 255 | #{Background} /opt/local/bin/pnmscale " + Res.to_s + " | " +
		"#{ImageCmd} -interlace -transparent rgb:#{Transparent} >#{Name}.#{ImageExt}";

	#run command
	system(cmd)

	#   Sweep up debris left around by the various intermediate steps
  system("rm #{Name}.dvi #{Name}.aux #{Name}.log _temp_#{Name}.ps #{Name}.tex ");

end

# utlize the above function to create our image - should be on the desktop now...
create_png(copied_text)

#so now we have a picture in the img folder with the name {Name} we want to copy and insert 

# --- Not used - now we get file url directly
#Use finder app to copy the new picture
# finder = app('Finder')
#get desktop
# desktop = finder.home.folders["Desktop"].get
#get pic we want
# pic = desktop.folders["img"].files["#{Name}.png"].get
#---

# need this to set the contents of the clipboard
sa = OSAX::ScriptingAddition.new("StandardAdditions")

# get the url for the image into the clipboard
sa.set_the_clipboard_to("file://#{root_folder}/img/#{Name}.png")

# So now we just need to get back to omnioutliner and put this in the correct position

#activate omnioutiner -- might remove to make more universal...
omni.activate

# use system events to paste
se.keystroke('v', :using=>[:command_down])

Prerequisites:

First you need all the programs needed for the original perl version. From my LaTeX install, I had everything except for Netpbm, and this was available through MacPorts.

You also need the AppleScript – ruby bridge rb-appscript. Hopefully I’ll post more on uses for this awesome framework, but essentially it allows you to execute AppleScript commands, but write them in ruby instead (which I find to be much less confusing / much more powerful). You can download it as a gem.

This code, as it is, can only be used with OmniOutliner Pro. It uses rb-appscript to find out where the currently open OmniOutliner document is, so that it can save the generated .png in a sub-directory (img) of that directory. If you wanted to make this more general, you could modify this portion to save all your generated files to the same place (~/Pictures/latex) regardless of what program you going to paste them in.

Also, if you do use OmniOutliner, you probably want to change an option in the Document: Display portion of the Inspector. Uncheck the “Show attachment tags” so that the pasted equation is immediately visible in the notes, instead of collapsed under its own tag.

Save your script as what ever, and then chmod it to add the executable flag.

The finishing touch — Quicksilver:

What Mac tutorial would be complete without a Quicksilver mention?

You can assign your newly created LaTeX script to its own Trigger (mine is option+command+l) to automate calling it. In fact, it would be hard to get it to work right without using a short-cut of some sort.

Now, to use, simply highlight the entirety of your equation, hit your shortcut key, and wait a few seconds (its not speedy). If your equation is without error, you should see it pop into your notes, perfectly capturing the knowledge being distributed by your professor at that moment in time.

Advertisements

3 Responses to Adding LaTeX to Notes with Ruby

  1. zedr0n says:

    – Nice article but there are some points I’d like to make
    – ‘require Date’ missing
    – I’ve spent a lot of time figuring out that when spawning the
    script from quicksilver the paths aren’t there so the absolute
    paths are needed in system calls. I’ve removed the paths at first
    – obviously it stopped working when called outside of terminal
    – gs and netpbm aren’t available on darwin by default
    – the ImageCmd and and ImageExt aren’t set
    – I assumed ImageCmd is pnmtopng and ImageExt is png but
    pnmtopng isn’t available in netpbm by default and
    building it isn’t as straightforward as configure/make
    unfortunately
    – se is app(“System Events”)?

  2. Tom Page says:

    Hey Jim,

    I don’t understand anything you wrote about, but I’m sure it’s cool. I’m going to start following your blog, so that your reader base will increase to 3.

    Peace,
    Tom

  3. J Chris A says:

    I thought this was helpful. LaTex is essential in mathematics and you gotta be knowing it.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: