Skip to content

Instantly share code, notes, and snippets.

@mattolson
Created April 9, 2013 15:20
Show Gist options
  • Save mattolson/5346598 to your computer and use it in GitHub Desktop.
Save mattolson/5346598 to your computer and use it in GitHub Desktop.
Script to reverse the tiling an image goes through when processed by Zoomify
#!/usr/bin/env ruby
require 'rubygems'
require 'fileutils'
require 'open-uri'
require 'rexml/document'
require 'tempfile'
require 'shellwords'
module Shell
# Exceptions
class CommandFailed < RuntimeError; end
def run(command, args="")
full_command = "#{command} #{escape_args(args)}"
puts "Running command: #{full_command}"
begin
result = `#{full_command}`
rescue Errno::ENOENT
raise_shell_command_failed(full_command)
end
if $?.exitstatus == 1
throw :unable_to_handle
elsif !$?.success?
raise_shell_command_failed(full_command)
end
end
def raise_shell_command_failed(command)
raise CommandFailed, "Command failed (#{command}) with exit status #{$?.exitstatus}"
end
def escape_args(args)
args.shellsplit.map do |arg|
quote arg.gsub(/\\?'/, %q('\\\\''))
end.join(' ')
end
def quote(s)
"'#{s}'"
end
end
class Zoomify
TILESIZE = 256
include Shell
def unzoomify(url, level=5)
@url = url
@level = level
@output_filename = "tmp/#{File.basename(@url)}.png"
# Read properties file
doc = nil
begin
open("#{@url}/ImageProperties.xml") do |f|
doc = REXML::Document.new(f)
end
rescue OpenURI::HTTPError
puts "ERROR: Failed to open ImageProperties.xml"
return nil
end
# Sanity check
attrs = doc.root.attributes
unless attrs['TILESIZE'] == TILESIZE.to_s && attrs['VERSION'] == '1.8'
puts "ERROR: unexpected tile size"
return nil
end
# Get properties
width = attrs['WIDTH'].to_i
height = attrs['HEIGHT'].to_i
num_tiles = attrs['NUMTILES'].to_i
num_tiles_x = width / TILESIZE
num_tiles_y = height / TILESIZE
@tile_groups = (0..num_tiles/TILESIZE).to_a
image = transparent(width, height)
(0..num_tiles_x).each do |column|
(0..num_tiles_y).each do |row|
# Get tile
filename = "#{@level}-#{column}-#{row}.jpg"
puts "Getting #{filename}..."
tile_image = get_tile(filename)
# Merge it into master image
composite!(tile_image, column*TILESIZE, row*TILESIZE) if tile_image
end
end
return @output_filename
end
def get_tile(filename)
@tile_groups.each do |group|
begin
tile_url = "#{@url}/TileGroup#{group}/#{filename}"
file_ext = ".#{File.extname(filename).split('.').last}"
tempfile = ::Tempfile.new ['unzoomify', file_ext]
tempfile.binmode
puts "Getting #{tile_url}..."
open(tile_url) do |f|
tempfile.write(f.read)
end
tempfile.close
return tempfile
rescue OpenURI::HTTPError, Errno::ENOENT
puts "Not found."
end
end
puts "WARNING: (#{@url}, #{filename}) appears to be missing or invalid"
nil
end
def transparent(width, height)
run :convert, %(-size #{width}x#{height} canvas:none #{@output_filename})
end
def composite!(tile, x, y)
run :composite, %(-compose src-over -geometry '#{TILESIZE}x#{TILESIZE}+#{x}+#{y}' #{tile.path} #{@output_filename} #{@output_filename})
end
end
z = Zoomify.new
full_image_path = z.unzoomify 'directory_or_url'
puts full_image_path ? "Full size image written to #{full_image_path}." : "ERROR"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment