Skip to content

Instantly share code, notes, and snippets.

@sr3d
Created May 25, 2010 20:10
Show Gist options
  • Save sr3d/413618 to your computer and use it in GitHub Desktop.
Save sr3d/413618 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'prawn'
require "prawn/measurement_extensions"
require 'ruby-debug'
balsamiq = "/Volumes/Macintosh HD/Applications/Balsamiq Mockups.app/Contents/MacOS/Balsamiq Mockups"
# Put ignored bmml files here, one per line
ignored_files = [
"blank.bmml",
"06.01.01.Events Management.bmml"
]
output_dir = "./output"
checkpoint_file = "#{output_dir}/checkpoint"
Dir.mkdir( output_dir ) unless ( File.exists?( output_dir ) or File.directory?( output_dir ) )
class JPEG
attr_reader :width, :height, :bits
def initialize(file)
if file.kind_of? IO
examine(file)
else
File.open(file, 'rb') { |io| examine(io) }
end
end
private
def examine(io)
raise 'malformed JPEG' unless io.getc == 0xFF && io.getc == 0xD8 # SOI
class << io
def readint; (readchar << 8) + readchar; end
def readframe; read(readint - 2); end
def readsof; [readint, readchar, readint, readint, readchar]; end
def next
c = readchar while c != 0xFF
c = readchar while c == 0xFF
c
end
end
while marker = io.next
case marker
when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF # SOF markers
length, @bits, @height, @width, components = io.readsof
raise 'malformed JPEG' unless length == 8 + components * 3
when 0xD9, 0xDA: break # EOI, SOS
when 0xFE: @comment = io.readframe # COM
when 0xE1: io.readframe # APP1, contains EXIF tag
else io.readframe # ignore frame
end
end
end
end
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 file
# http://snippets.dzone.com/posts/show/805
case file
when /\.png$/i
IO.read( file )[0x10..0x18].unpack('LL')
when /\.gif$/i
IO.read( file )[6..10].unpack('SS')
when /\.jpe?g$/i
jpg = JPEG.new( file )
return [ jpg.width, jpg.height ]
end
end
end
# remove files in Output but not in input
images = Dir.glob "#{output_dir}/*.png"
files = Dir.glob "*.bmml" || {}
images.each do |image|
if files.collect{ |file| file if image.index(file) == 0 }.compact.empty?
puts "[DELETE] #{output_dir}/{image} (old files)"
File.delete "#{output_dir}/#{image}"
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 ||= {}
#puts files
# debugger
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 PNG)"
next_run[ file ] = File.mtime( file )
else
puts "[REUSE] #{file} (same as last time)"
end
images << "#{output_dir}/#{file}.png"
end
# now export
# images = [ "#{output_dir}/Screen shot 2010-05-24 at 12.24.02 AM.png",
# "#{output_dir}/Screen shot 2010-05-24 at 12.22.28 AM.png",
# "#{output_dir}/Screen shot 2010-05-25 at 2.22.01 PM.png"
# ]
next_run.each do |file, mtime|
puts "[EXPORT] #{file}"
cmd = %!"#{balsamiq}" export "#{File.expand_path file}" "#{File.expand_path("#{output_dir}/#{file}.png") }"!
puts cmd
`#{cmd}`
break
end
# Baill out if there's no images
return if images.empty?
# Read the first image size to determine the initial layout
dim = Util.dimension_of images.first
Prawn::Document.generate( "#{output_dir}/mocks.pdf", :page_size => "A4", :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 )
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment