Skip to content

Instantly share code, notes, and snippets.

@sr3d
Created May 28, 2010 16:13
Show Gist options
  • Save sr3d/417354 to your computer and use it in GitHub Desktop.
Save sr3d/417354 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# This script will automatically export all the Balsamiq mock files to PDF and bundle them up
# into a nice PDF. Just drop this script into the folder containing the mock files and
# execute it from the command-line
#
# For the PDF to work, you'd need to install "prawn" and "prawn-fast-png" gem, otherwise the PDF
# creation will be very slow.
#
# Currently this script has been tested with Balsamiq Next.161 build (05/28/2010)
# and Ruby 1.8.7 running on Snow Leopard
#
require 'rubygems'
require 'prawn'
require "prawn/measurement_extensions"
require 'prawn/fast_png'
require 'ruby-debug'
balsamiq = "/Volumes/Macintosh HD/Applications/Balsamiq Mockups.app/Contents/MacOS/Balsamiq Mockups"
output_dir = "./output" # output folder for images
output_format = "png" # The format that Balsamiq would export. Currently png only
remove_old_images_from_output_dir = true # Remove images in the Output folder and not in Input folder
ignored_files = [ # Any files in this array will be skipped. File name is case-sensitive
"blank.bmml",
"ANOTHER_FILE.bmml"
]
export_to_pdf = true # Export to output_dir/mock.pdf
output_pdf = "#{output_dir}/mock.pdf" # Where the PDF file should be exported to
paper_size = 'A4' # how big the page should be
# Setting up output dir to not clutter up the current folder
Dir.mkdir( output_dir ) unless ( File.exists?( output_dir ) or File.directory?( output_dir ) )
class Util
def self.store obj, file_name
marshal_dump = Marshal.dump(obj)
file = File.new(file_name,'w')
file.write marshal_dump
file.close
return obj
end
def self.load file_name
return nil unless File.exists? file_name
file = File.open(file_name, 'r')
obj = Marshal.load file.read
file.close
return obj
end
def self.dimension_of png_file
IO.read( png_file )[0x10..0x18].unpack('LL')
end
end
# Time a running block.
def time( msg )
start = Time.now
puts "Begin #{msg}"
yield
puts "Finish #{msg} . Time elapsed: #{Time.now - start} seconds"
end
# File to save last run info about the files
checkpoint_file = "#{output_dir}/checkpoint"
# remove files in Output but not in input
if remove_old_images_from_output_dir
images = Dir.glob "#{output_dir}/*.#{output_format}"
files = Dir.glob "*.bmml" || {}
images.each do |image|
if files.collect{ |file| file if image.index(file) and image.index(file) > 0 }.compact.empty?
puts "[DELETE] #{output_dir}/#{image} (old files)"
File.delete "#{image}"
end
end
end
puts "==========="
# read in checkpoint file so that we can skip already generated files that are unchanged
last_run = Util.load checkpoint_file
last_run ||= {}
images = []
next_run = {}
files.each do |file|
next if ignored_files.index( file )
if last_run[ file ] != File.mtime( file )
puts "[ADD] #{file} (to be exported to #{output_format})"
next_run[ file ] = File.mtime( file )
else
puts "[REUSE] #{file} (same as last time)"
end
# Enqueue the image to be generated and included in the PDF
images << "#{output_dir}/#{file}.#{output_format}"
end
# now export
time "Exporting Mocks" do
next_run.each do |file, mtime|
puts "[EXPORT] #{file}"
cmd = %!"#{balsamiq}" export "#{File.expand_path file}" "#{File.expand_path("#{output_dir}/#{file}.#{output_format}") }"!
#puts cmd
`#{cmd}`
end
end
if export_to_pdf
# Baill out if there's no images
return if images.empty?
# Read the first image size to determine the initial layout
time "Creating PDF" do
dim = Util.dimension_of images.first
i = 0
Prawn::Document.generate( "#{output_dir}/mocks.pdf", :page_size => paper_size, :page_layout => dim[1] > dim [ 0 ] ? :portrait : :landscape ) do
# Append image to the pdf document
images.each_with_index do |img, i|
dim = Util.dimension_of( img )
puts "PDF << #{img} (page #{i+1})"
start_new_page( :layout => dim[1] > dim [ 0 ] ? :portrait : :landscape ) if i > 0
image img, :position => :left, :vposition => :top , :fit => bounds.top_right
end
# Print the page #
number_pages "<page>", [bounds.left, 0]
# build the section outline
define_outline do
section 'Mock', :page => 1, :closed => true do
for i in 0...images.length
page i + 1, :title => images[i].split('/').last
end
end
end
end
end
end
# Saving
puts "Saving checkpoint file"
Util.store last_run.merge( next_run ), checkpoint_file
puts "DONE"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment