tileup 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/tileup +44 -0
- data/lib/tileup.rb +142 -0
- metadata +63 -0
data/bin/tileup
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tileup'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
# auto zoom bigmap.png down 4 times, output to map-tiles dir with map-tile-X-Y.png filename
|
7
|
+
# maw --in "bigmap.png" --auto-zoom --auto-zoom-levels 4 --output-dir "map-tiles" --filename-prefx="map-tile"
|
8
|
+
|
9
|
+
# maw --in "bigmap.png" --output-dir "map-tiles/20/" --filename-prefix="map-tile" --tile-width 256 --tile-height 256
|
10
|
+
|
11
|
+
|
12
|
+
options = {
|
13
|
+
tile_width: 256,
|
14
|
+
tile_height: 256,
|
15
|
+
filename_prefix: "map_tile",
|
16
|
+
auto_zoom_levels: nil,
|
17
|
+
input_filename: nil,
|
18
|
+
output_dir: '.'
|
19
|
+
|
20
|
+
}
|
21
|
+
|
22
|
+
OptionParser.new do |o|
|
23
|
+
o.on('--in=input_file', " Required input file, your large image to tile up") { |input_filename| options[:input_filename] = input_filename }
|
24
|
+
o.on('--prefix=map_tile', "Prefix to append to tile files, e.g. --prefix=my_tile => my_tile_[XN]_[YN].png") { |prefix| options[:filename_prefix] = prefix }
|
25
|
+
o.on('--tile-width=256', "Tile width, should normally equal tile height") { |width| options[:tile_width] = width }
|
26
|
+
o.on('--tile-height=256', "Tile height, should normally equal tile width") { |height| options[:tile_height] = height }
|
27
|
+
o.on('--auto-zoom=', Integer, "Automatically scale input image N times, must be a number"){ |zooms| options[:auto_zoom_levels] = zooms }
|
28
|
+
o.on('--output-dir=', "Output directory (will be created if it doesn't exist)") { |output_dir| options[:output_dir] = output_dir }
|
29
|
+
o.on('-v', '--verbose', "Enable verbose logging") { |verbose| options[:verbose] = true }
|
30
|
+
o.on('-h', '--help', "You're looking at it.") { puts o; exit }
|
31
|
+
begin
|
32
|
+
o.parse!
|
33
|
+
rescue Exception => e
|
34
|
+
puts "Argument error, #{e.message}. Try running '#{File.basename($PROGRAM_NAME)} -h'"
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if options[:input_filename].nil?
|
40
|
+
puts "No input file specified, Try running '#{File.basename($PROGRAM_NAME)} -h'"
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
|
44
|
+
TileUp::Tiler.new(options[:input_filename], options)
|
data/lib/tileup.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'rmagick'
|
3
|
+
|
4
|
+
module TileUp
|
5
|
+
|
6
|
+
class Tiler
|
7
|
+
|
8
|
+
def initialize(image_filename, options)
|
9
|
+
default_options = {
|
10
|
+
auto_zoom_levels: nil,
|
11
|
+
tile_width: 256,
|
12
|
+
tile_height: 256,
|
13
|
+
filename_prefix: "map_tile",
|
14
|
+
output_dir: ".",
|
15
|
+
verbose: false
|
16
|
+
}
|
17
|
+
@options = OpenStruct.new(default_options.merge(options))
|
18
|
+
@extension = image_filename.split(".").last
|
19
|
+
@filename_prefix = @options.filename_prefix
|
20
|
+
|
21
|
+
begin
|
22
|
+
@image = Magick::Image::read(image_filename).first
|
23
|
+
rescue Magick::ImageMagickError => e
|
24
|
+
puts "Could not open image #{image_filename}."
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
if @options.auto_zoom_levels && @options.auto_zoom_levels > 20
|
29
|
+
puts "Warning: auto zoom levels hard limited to 20."
|
30
|
+
@options.auto_zoom_levels = 20
|
31
|
+
end
|
32
|
+
if @options.auto_zoom_levels && @options.auto_zoom_levels <= 0
|
33
|
+
@options.auto_zoom_levels = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "Opened #{image_filename}, #{@image.columns} x #{@image.rows}"
|
37
|
+
|
38
|
+
# pre-process our inputs to work out what we're supposed to do
|
39
|
+
tasks = []
|
40
|
+
|
41
|
+
if @options.auto_zoom_levels.nil?
|
42
|
+
# if we have no auto zoom request, then
|
43
|
+
# we dont shrink or scale, and save directly to the output
|
44
|
+
# dir.
|
45
|
+
tasks << {
|
46
|
+
output_dir: @options.output_dir, # normal output dir
|
47
|
+
scale: 1.0 # dont scale
|
48
|
+
}
|
49
|
+
else
|
50
|
+
# do have zoom levels, so construct those tasks
|
51
|
+
zoom_name = 20
|
52
|
+
scale = 1.0
|
53
|
+
tasks << {
|
54
|
+
output_dir: File.join(@options.output_dir, zoom_name.to_s),
|
55
|
+
scale: scale
|
56
|
+
}
|
57
|
+
(@options.auto_zoom_levels-1).times do |level|
|
58
|
+
scale = scale / 2.0
|
59
|
+
zoom_name = zoom_name - 1
|
60
|
+
tasks << {
|
61
|
+
output_dir: File.join(@options.output_dir, zoom_name.to_s),
|
62
|
+
scale: scale
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# run through tasks list
|
68
|
+
tasks.each do |task|
|
69
|
+
image = @image
|
70
|
+
image_path = File.join(task[:output_dir], @filename_prefix)
|
71
|
+
if task[:scale] != 1.0
|
72
|
+
# if scale required, scale image
|
73
|
+
begin
|
74
|
+
image = @image.scale(task[:scale])
|
75
|
+
rescue RuntimeError => e
|
76
|
+
message = "Failed to scale image, are you sure the original image "\
|
77
|
+
"is large enough to scale down this far (#{scale}) with this "\
|
78
|
+
"tilesize (#{@options.tile_width}x#{@options.tile_height})?"
|
79
|
+
puts message
|
80
|
+
exit
|
81
|
+
end
|
82
|
+
end
|
83
|
+
# make output dir
|
84
|
+
make_path(task[:output_dir])
|
85
|
+
self.make_tiles(image, image_path, @options.tile_width, @options.tile_height)
|
86
|
+
image = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
puts "Finished."
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
def make_path(directory_path)
|
94
|
+
parts = directory_path.split(File::SEPARATOR);
|
95
|
+
parts.each_index do |i|
|
96
|
+
upto = parts[0..i].join(File::SEPARATOR)
|
97
|
+
Dir::mkdir(upto) unless Dir::exists?(upto)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def make_tiles(image, filename_prefix, tile_width, tile_height)
|
102
|
+
# find image width and height
|
103
|
+
# then find out how many tiles we'll get out of
|
104
|
+
# the image, then use that for the xy offset in crop.
|
105
|
+
num_columns = image.columns/tile_width
|
106
|
+
num_rows = image.rows/tile_height
|
107
|
+
x,y,column,row = 0,0,0,0
|
108
|
+
crops = []
|
109
|
+
|
110
|
+
puts "Tiling image into columns: #{num_columns}, rows: #{num_rows}"
|
111
|
+
|
112
|
+
while true
|
113
|
+
x = column * tile_width
|
114
|
+
y = row * tile_height
|
115
|
+
crops << {
|
116
|
+
x: x,
|
117
|
+
y: y,
|
118
|
+
row: row,
|
119
|
+
column: column
|
120
|
+
}
|
121
|
+
column = column + 1
|
122
|
+
if column >= num_columns
|
123
|
+
column = 0
|
124
|
+
row = row + 1
|
125
|
+
end
|
126
|
+
if row >= num_rows
|
127
|
+
break
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
crops.each do |c|
|
132
|
+
ci = image.crop(c[:x], c[:y], tile_width, tile_height, true);
|
133
|
+
print "Saving tile: #{c[:row]}, #{c[:column]}..." if @options.verbose
|
134
|
+
ci.write("#{filename_prefix}_#{c[:column]}_#{c[:row]}.#{@extension}")
|
135
|
+
print "\rSaving tile: #{c[:row]}, #{c[:column]}... saved\n" if @options.verbose
|
136
|
+
ci = nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tileup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Oliver Marriott
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rmagick
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.13.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.13.2
|
30
|
+
description: Turn an image into an X,Y tile set for use with JS mapping libraries
|
31
|
+
email: hello@omarriott.com
|
32
|
+
executables:
|
33
|
+
- tileup
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- lib/tileup.rb
|
38
|
+
- bin/tileup
|
39
|
+
homepage: http://rubygems.org/gems/tileup
|
40
|
+
licenses: []
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.8.25
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: Turn an image into an X,Y tile set for use with JS mapping libraries
|
63
|
+
test_files: []
|