Creating ready-to-print photo books with Ruby and TeX
Ruby Beats Go
Why use Ruby for the glue code and not Go, which has become the de facto choice in this Programming Snapshot column, you ask? Well, a scripting language like Ruby simply can't be beaten for plain vanilla text manipulation and simple, concise, easy-to-extend code that almost looks like a config file. On top of that, Ruby's template system ERB is great for dumping text or picture file names into predefined snippets with a mess of TeX code. There is a good reason why configuration management tools like Puppet and Chef use Ruby as a reference language for dynamically adapting variegated configuration files catering to individual environments.
Listing 2 shows you the Ruby glue code to turn the book description scripts into TeX. It defines a class that user scripts need to include to generate coffee table books, just like Listing 1 does in line 2. Scripts call the built-in Ruby function require_relative bm
to find the library from Listing 2 in the same directory and can then immediately get started by calling Bm.new
. The returned bm
instance then lets you create sophisticated photo books with just a few commands.
Listing 2
bm.rb
01 #!/usr/bin/ruby 02 require 'erb' 03 04 class Bm 05 attr_accessor :name 06 07 def initialize 08 @tmpldir = "tmpl" 09 @photodir = "photos" 10 @tex = "" 11 end 12 13 def add(tmpl, text: "", photos: []) 14 tpath = "#{@tmpldir}/#{tmpl}.tex" 15 16 photos = photos.map { 17 |path| "#{@photodir}/#{path}"} 18 19 t = ERB.new(File.read(tpath)) 20 @tex += t.result_with_hash( 21 text: text, photos: photos) 22 end 23 24 def print 25 texf = "#{@name}.tex" 26 File.open(texf, "w") { 27 |f| f.write(@tex) } 28 system("xelatex", texf) 29 end 30 end
Short Paths
To keep things tidy, the predefined TeX templates are all located in a subdirectory named tmpl/
. To help the user call them by simple names, such as cover
, Listing 2 defines an @tmpldir
instance variable that points to the subdirectory containing the templates. When it's time to load a template, line 14 prepends the tmpl
path to the provided file name and adds a .tex
suffix thereafter. This means that the generated path points to a real file, which the ERB template processor can then read from disk in line 19.
The template processor uses ERB
's result_with_hash()
method in line 20 to insert the text supplied for the page caption, and the paths to the photo files, into the respective template. The placeholders in the templates are <%= text %>
for the page text and <%= photos[0] %>
for the first element of the photos
array passed in, containing a list of JPEG paths to the photos to be included. For the image paths, there is no need to laboriously type in the entire path each time. As long as the @photodir
instance variable is pointing to the directory where all the images are stored (photos
in our example), you only need to specify the file name without a path in each case in Listing 1.
Defining the Name
To define the name of the book file to be created, the calling script sets the name
attribute of a Bm
object as shown in line 5 of Listing 1. To make this work, Listing 2 uses attr_accessor
in line 5 to define :name
and with it a read-write attribute name
for all objects of the class.
This means that an instance of the Bm
class in bm
can simply call bm.name = "mybook"
, like it does in line 5 of Listing 1, to set the book name by assignment. Line 25 in Listing 2 uses @name
to obtain the name from the instance variable and interpolates it within a string with "#{@name}"
. This gives you the name of the TeX file with all the piled up TeX code and will send the file to the XeLaTeX LaTeX compiler in the next step.
This means that line 26 only needs to open the .tex
file for writing and drop the content of the @tex
instance variable there, after having assembled all the necessary TeX instructions in it. The system()
call in line 28 then runs XeLaTeX against this, which produces a PDF document of the same name with the finished photo book, if all goes well.
« Previous 1 2 3 4 Next »
Buy this article as PDF
(incl. VAT)