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.
Files changed (3) hide show
  1. data/bin/tileup +44 -0
  2. data/lib/tileup.rb +142 -0
  3. 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: []