Created
April 9, 2013 15:20
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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