tileup 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|