Skip to content

Instantly share code, notes, and snippets.

@miletbaker
Created October 9, 2011 19:11
Show Gist options
  • Save miletbaker/1274032 to your computer and use it in GitHub Desktop.
Save miletbaker/1274032 to your computer and use it in GitHub Desktop.
Ruby script to scale and crop an image into overlay or map tiles for use with Google Maps API, Javascript for display custom map tiles below.
#! /usr/bin/ruby -w
require 'rubygems'
require 'rmagick'
require 'fileutils'
include Magick
ARGV.each do |file|
puts "Processing #{file}"
# Check file exists
unless File::exists?( file )
puts "Image #{file} not found"
next
end
#Setup
img_name = File.basename(file, ".jpg")
# Load the source image and a little information
img = Magick::Image.read(file).first
w = img.columns
h = img.rows
puts "Image #{file} too small (<512x512)" and next unless (h > 512 || w > 512)
FileUtils.rm_rf(img_name) if File::directory?(img_name)
Dir.mkdir(img_name)
# Find the next largest multiple of 256 and the power of 2
dim = w > h ? w : h
pow = -1
loop do
i = 256*(2**pow+=1)
next if i < dim
dim = i
break
end
# Resize the source image up to the larger size
if (dim > w && dim > h)
puts "Resizing image to #{dim}px"
# Determine the optimal pixel radius for sharpening
img.change_geometry!("#{dim}x#{dim}") { |cols, rows, i|
i.resize!(cols, rows)
}
sharp = ( w/dim > h/dim ? dim/w : dim/h )/2
img = img.sharpen(sharp)
end
# Build a new square image with a black background, and composite the source image on top of it.
master = Magick::Image.new(dim,dim){ self.background_color = "#E4E3DF" }
master.composite!(img, Magick::CenterGravity, Magick::OverCompositeOp)
img = nil
# Create slice layers
layer = 0
loop do
# Google Maps only allows 19 layers (though I doubt we'll ever reach this point).
break if layer > 18
width = 256*(2**layer)
break if width > dim
Dir.mkdir("#{img_name}/#{layer}", 0775) unless File::directory?("#{img_name}/#{layer}")
crop_master = master.clone
crop_master.resize!(width, width)
max_loop = (width / 256) - 1
(0 .. max_loop).each do |x|
(0 .. max_loop).each do |y|
crop = crop_master.clone
crop.crop!( x*256, crop_master.rows - ((y + 1) * 256), 256, 256)
crop.write("#{img_name}/#{layer}/#{x}-#{y}.jpg")
crop = nil
end
end
layer+=1
crop_master = nil
end
master = nil
end
var map;
function loadMap(){
var maptiler = new google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
if (coord.x < 0 || (Math.pow(2,zoom)-coord.y-1) < 0 || (Math.pow(2,zoom)-coord.y-1) >= Math.pow(2,zoom) || coord.x >= Math.pow(2,zoom))
return "/system/blank.jpg";
else
return "/system/" + map_loc + "/" + zoom + "/" + coord.x + "-" + (Math.pow(2,zoom)-coord.y-1) + ".jpg";
},
tileSize: new google.maps.Size(256, 256),
maxZoom: map_max_zoom,
minZoom: map_min_zoom,
name:'Paris'
});
map = new google.maps.Map(document.getElementById("map"), {streetViewControl: false, mapTypeControl: false});
map.mapTypes.set('paris', maptiler);
map.setMapTypeId('paris');
map.setCenter(new google.maps.LatLng(map_lat, map_lon));
map.setZoom(map_init_zoom);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment