tileup 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.md +34 -0
- data/LICENCE.txt +22 -0
- data/README.md +73 -0
- data/bin/tileup +13 -9
- data/lib/tileup.rb +2 -151
- data/lib/tileup/logger.rb +96 -0
- data/lib/tileup/tiler.rb +160 -0
- data/lib/tileup/version.rb +3 -0
- data/tileup.gemspec +24 -0
- metadata +45 -4
data/CHANGES.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Tileup Change Log
|
2
|
+
=================
|
3
|
+
|
4
|
+
v0.1.4
|
5
|
+
------
|
6
|
+
|
7
|
+
- Fix: Background color for extended tiles (now transparent instead of white,
|
8
|
+
which would clobber transparent backgrounds)
|
9
|
+
|
10
|
+
v0.1.3
|
11
|
+
------
|
12
|
+
|
13
|
+
- New: Functionality to automatically pad tiles that are not tile_width x tile_height
|
14
|
+
- New: CLI switch to disable functionality (`dont-extend-incomplete-tiles`)
|
15
|
+
|
16
|
+
v0.1.2
|
17
|
+
------
|
18
|
+
|
19
|
+
- Lost to history
|
20
|
+
|
21
|
+
v0.1.1
|
22
|
+
------
|
23
|
+
|
24
|
+
- Lost to history
|
25
|
+
|
26
|
+
v0.1.0
|
27
|
+
------
|
28
|
+
|
29
|
+
- Lost to history
|
30
|
+
|
31
|
+
v0.0.1
|
32
|
+
------
|
33
|
+
|
34
|
+
- Lost to history
|
data/LICENCE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Oliver Marriott
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
Tile Up
|
2
|
+
=======
|
3
|
+
|
4
|
+
*Tile Up* is a ruby Ruby gem that splits a large image into a set of tiles to use with javascript mapping libraries such as [Leaflet.js](http://leafletjs.com) or [Modest Maps](http://modestmaps.com/). You can also use *Tile Up* to make tiles for `CATiledLayer` (or anything else really...).
|
5
|
+
|
6
|
+
Installation
|
7
|
+
------------
|
8
|
+
|
9
|
+
`gem install tileup`
|
10
|
+
|
11
|
+
`tileup` requires `rmagick` for image manipulation, which depends on `imagemagick`. `imagemagick` is avaliable through `homebrew`.
|
12
|
+
|
13
|
+
Usage
|
14
|
+
-----
|
15
|
+
|
16
|
+
### Basics
|
17
|
+
|
18
|
+
To generate some tiles from a large image, you'll probably use something like:
|
19
|
+
|
20
|
+
```
|
21
|
+
tileup --in huge_image.png --output-dir image_tiles \
|
22
|
+
--prefix my_tiles --verbose
|
23
|
+
```
|
24
|
+
|
25
|
+
Which will split `huge_image.png` up into `256x256` (default) sized tiles, and save them into the directory `image_tiles`. The images will be saved as `my_tiles_[COLUMN]_[ROW].png`
|
26
|
+
|
27
|
+
```
|
28
|
+
image_tiles/my_tiles_0_0.png
|
29
|
+
image_tiles/my_tiles_0_1.png
|
30
|
+
image_tiles/my_tiles_0_2.png
|
31
|
+
...
|
32
|
+
```
|
33
|
+
|
34
|
+
### Auto zooming
|
35
|
+
|
36
|
+
`tileup` can also scale your image for a number of zoom levels (max 20 levels). This is done by *scaling down* the original image, so make sure its pretty big.
|
37
|
+
|
38
|
+
*(Auto zooming is an experimental hack, it should work fine for smaller increments, but may be unreliable at higher levels. E.g. `--auto-zoom 4` should work fine, `--auto-zoom 20` might not work so well.)*
|
39
|
+
|
40
|
+
```
|
41
|
+
tileup --in really_huge_image.png --auto-zoom 4 \
|
42
|
+
--output-dir map_tiles
|
43
|
+
```
|
44
|
+
|
45
|
+
`--auto-zoom 4` means, make 4 levesl of zoom, starting from `really_huge_image.png` at zoom level 20, then scale that down for 19, etc.
|
46
|
+
|
47
|
+
You should see something like:
|
48
|
+
|
49
|
+
```
|
50
|
+
map_tiles/20/map_tile_0_0.png
|
51
|
+
map_tiles/20/map_tile_0_1.png
|
52
|
+
map_tiles/20/map_tile_0_2.png
|
53
|
+
...
|
54
|
+
map_tiles/19/map_tile_0_0.png
|
55
|
+
map_tiles/19/map_tile_0_1.png
|
56
|
+
map_tiles/19/map_tile_0_2.png
|
57
|
+
...
|
58
|
+
```
|
59
|
+
*(where `20` is zoom level 20, the largest zoom, `19` is half the size of `20`, `18` is half the size of `19`, …)*
|
60
|
+
|
61
|
+
|
62
|
+
### Getting help
|
63
|
+
|
64
|
+
You can get help by running `tileup -h`.
|
65
|
+
|
66
|
+
Contributing
|
67
|
+
------------
|
68
|
+
|
69
|
+
Fixes and patches welcome, to contribute:
|
70
|
+
|
71
|
+
1. Fork this project
|
72
|
+
1. Create a feature or fix branch *off the develop branch*
|
73
|
+
1. Submit a pull request on that branch
|
data/bin/tileup
CHANGED
@@ -3,12 +3,6 @@
|
|
3
3
|
require 'tileup'
|
4
4
|
require 'optparse'
|
5
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
6
|
options = {
|
13
7
|
tile_width: 256,
|
14
8
|
tile_height: 256,
|
@@ -20,19 +14,24 @@ options = {
|
|
20
14
|
}
|
21
15
|
|
22
16
|
OptionParser.new do |o|
|
23
|
-
o.on('--in=input_file', "
|
17
|
+
o.on('--in=input_file', "Required input file, your large image to tile up.") { |input_filename| options[:input_filename] = input_filename }
|
24
18
|
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
19
|
o.on('--tile-width=256', "Tile width, should normally equal tile height.") { |width| options[:tile_width] = width }
|
26
20
|
o.on('--tile-height=256', "Tile height, should normally equal tile width.") { |height| options[:tile_height] = height }
|
27
21
|
o.on('--auto-zoom=', Integer, "Automatically scale input image N times, must be a number."){ |zooms| options[:auto_zoom_levels] = zooms }
|
28
22
|
o.on('--output-dir=', "Output directory (will be created if it doesn't exist).") { |output_dir| options[:output_dir] = output_dir }
|
29
23
|
o.on('--dont-extend-incomplete-tiles',
|
30
|
-
"Do not extend edge tiles if they do not fill an entire tile_width x tile_height.
|
24
|
+
"Do not extend edge tiles if they do not fill an entire tile_width x tile_height. " +
|
25
|
+
"By default tileup will extend tiles to tile_width x tile_height if required.") {|e|options[:extend_incomplete_tiles] = false}
|
31
26
|
o.on('-v', '--verbose', "Enable verbose logging.") { |verbose| options[:verbose] = true }
|
32
27
|
o.on('-h', '--help', "You're looking at it.") { puts o; exit }
|
28
|
+
o.on('--version', "Version information (v#{TileUp::VERSION})") { puts TileUp::VERSION; exit }
|
33
29
|
begin
|
34
30
|
o.parse!
|
31
|
+
rescue SystemExit => e
|
32
|
+
exit
|
35
33
|
rescue Exception => e
|
34
|
+
puts e.class
|
36
35
|
puts "Argument error, #{e.message}. Try running '#{File.basename($PROGRAM_NAME)} -h'"
|
37
36
|
exit
|
38
37
|
end
|
@@ -43,4 +42,9 @@ if options[:input_filename].nil?
|
|
43
42
|
exit 1
|
44
43
|
end
|
45
44
|
|
46
|
-
|
45
|
+
begin
|
46
|
+
TileUp::Tiler.new(options[:input_filename], options)
|
47
|
+
rescue Interrupt
|
48
|
+
puts "\n\nInterrupt received, exiting.\n"
|
49
|
+
exit
|
50
|
+
end
|
data/lib/tileup.rb
CHANGED
@@ -1,151 +1,2 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'fileutils'
|
4
|
-
|
5
|
-
module TileUp
|
6
|
-
|
7
|
-
class Tiler
|
8
|
-
|
9
|
-
def initialize(image_filename, options)
|
10
|
-
default_options = {
|
11
|
-
auto_zoom_levels: nil,
|
12
|
-
tile_width: 256,
|
13
|
-
tile_height: 256,
|
14
|
-
filename_prefix: "map_tile",
|
15
|
-
output_dir: ".",
|
16
|
-
extend_incomplete_tiles: true,
|
17
|
-
verbose: false
|
18
|
-
}
|
19
|
-
@options = OpenStruct.new(default_options.merge(options))
|
20
|
-
@options.tile_width = @options.tile_width.to_i unless !@options.tile_width.respond_to? :to_i
|
21
|
-
@options.tile_height = @options.tile_height.to_i unless !@options.tile_height.respond_to? :to_i
|
22
|
-
@extension = image_filename.split(".").last
|
23
|
-
@filename_prefix = @options.filename_prefix
|
24
|
-
|
25
|
-
begin
|
26
|
-
@image = Magick::Image::read(image_filename).first
|
27
|
-
rescue Magick::ImageMagickError => e
|
28
|
-
puts "Could not open image #{image_filename}."
|
29
|
-
exit
|
30
|
-
end
|
31
|
-
|
32
|
-
if @options.auto_zoom_levels && @options.auto_zoom_levels > 20
|
33
|
-
puts "Warning: auto zoom levels hard limited to 20."
|
34
|
-
@options.auto_zoom_levels = 20
|
35
|
-
end
|
36
|
-
if @options.auto_zoom_levels && @options.auto_zoom_levels <= 0
|
37
|
-
@options.auto_zoom_levels = nil
|
38
|
-
end
|
39
|
-
|
40
|
-
puts "Opened #{image_filename}, #{@image.columns} x #{@image.rows}"
|
41
|
-
|
42
|
-
# pre-process our inputs to work out what we're supposed to do
|
43
|
-
tasks = []
|
44
|
-
|
45
|
-
if @options.auto_zoom_levels.nil?
|
46
|
-
# if we have no auto zoom request, then
|
47
|
-
# we dont shrink or scale, and save directly to the output
|
48
|
-
# dir.
|
49
|
-
tasks << {
|
50
|
-
output_dir: @options.output_dir, # normal output dir
|
51
|
-
scale: 1.0 # dont scale
|
52
|
-
}
|
53
|
-
else
|
54
|
-
# do have zoom levels, so construct those tasks
|
55
|
-
zoom_name = 20
|
56
|
-
scale = 1.0
|
57
|
-
tasks << {
|
58
|
-
output_dir: File.join(@options.output_dir, zoom_name.to_s),
|
59
|
-
scale: scale
|
60
|
-
}
|
61
|
-
(@options.auto_zoom_levels-1).times do |level|
|
62
|
-
scale = scale / 2.0
|
63
|
-
zoom_name = zoom_name - 1
|
64
|
-
tasks << {
|
65
|
-
output_dir: File.join(@options.output_dir, zoom_name.to_s),
|
66
|
-
scale: scale
|
67
|
-
}
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# run through tasks list
|
72
|
-
tasks.each do |task|
|
73
|
-
image = @image
|
74
|
-
image_path = File.join(task[:output_dir], @filename_prefix)
|
75
|
-
if task[:scale] != 1.0
|
76
|
-
# if scale required, scale image
|
77
|
-
begin
|
78
|
-
image = @image.scale(task[:scale])
|
79
|
-
rescue RuntimeError => e
|
80
|
-
message = "Failed to scale image, are you sure the original image "\
|
81
|
-
"is large enough to scale down this far (#{scale}) with this "\
|
82
|
-
"tilesize (#{@options.tile_width}x#{@options.tile_height})?"
|
83
|
-
puts message
|
84
|
-
exit
|
85
|
-
end
|
86
|
-
end
|
87
|
-
# make output dir
|
88
|
-
make_path(task[:output_dir])
|
89
|
-
self.make_tiles(image, image_path, @options.tile_width, @options.tile_height)
|
90
|
-
image = nil
|
91
|
-
end
|
92
|
-
|
93
|
-
puts "Finished."
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
def make_path(directory_path)
|
98
|
-
FileUtils.mkdir_p directory_path
|
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.to_f).ceil
|
106
|
-
num_rows = (image.rows/tile_height.to_f).ceil
|
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
|
-
|
134
|
-
# unless told to do otherwise, extend tiles in the last row and column
|
135
|
-
# if they do not fill an entire tile width and height.
|
136
|
-
if @options.extend_incomplete_tiles && (c[:row] == num_rows - 1 || c[:column] == num_columns - 1)
|
137
|
-
# fill to width height, start from top left corner.
|
138
|
-
ci = ci.extent(tile_width, tile_height, 0, 0)
|
139
|
-
end
|
140
|
-
|
141
|
-
print "Saving tile: #{c[:row]}, #{c[:column]}..." if @options.verbose
|
142
|
-
ci.write("#{filename_prefix}_#{c[:column]}_#{c[:row]}.#{@extension}")
|
143
|
-
print "\rSaving tile: #{c[:row]}, #{c[:column]}... saved\n" if @options.verbose
|
144
|
-
|
145
|
-
ci = nil
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
end
|
1
|
+
require 'tileup/tiler'
|
2
|
+
require 'tileup/version'
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module TileUp
|
5
|
+
|
6
|
+
# Base logger class, subclass this, do not use directly.
|
7
|
+
class TileUpLogger
|
8
|
+
|
9
|
+
def self.sym_to_severity(sym)
|
10
|
+
severities = {
|
11
|
+
:debug => Logger::DEBUG,
|
12
|
+
:info => Logger::INFO,
|
13
|
+
:warn => Logger::WARN,
|
14
|
+
:error => Logger::ERROR,
|
15
|
+
:fatal => Logger::FATAL
|
16
|
+
}
|
17
|
+
severity = severities[sym] || Logger::UNKNOWN
|
18
|
+
end
|
19
|
+
|
20
|
+
# create logger set to given level
|
21
|
+
# where level is a symbol (:debug, :info, :warn, :error, :fatal)
|
22
|
+
# options may specifiy verbose, which will log more info messages
|
23
|
+
def initialize(level, options)
|
24
|
+
@severity = level
|
25
|
+
default_options = {
|
26
|
+
verbose: false
|
27
|
+
}
|
28
|
+
@options = OpenStruct.new(default_options.merge(options))
|
29
|
+
end
|
30
|
+
|
31
|
+
def level
|
32
|
+
@level
|
33
|
+
end
|
34
|
+
|
35
|
+
def level=(severity)
|
36
|
+
logger.level = TileUpLogger.sym_to_severity(severity)
|
37
|
+
end
|
38
|
+
|
39
|
+
# log an error message
|
40
|
+
def error(message)
|
41
|
+
# note, we always log error messages
|
42
|
+
add(:error, message)
|
43
|
+
end
|
44
|
+
|
45
|
+
# log a regular message
|
46
|
+
def info(message)
|
47
|
+
add(:info, message)
|
48
|
+
end
|
49
|
+
|
50
|
+
def warn(message)
|
51
|
+
add(:warn, message)
|
52
|
+
end
|
53
|
+
|
54
|
+
# log a verbose message
|
55
|
+
def verbose(message)
|
56
|
+
add(:info, message) if verbose?
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# add message to log
|
62
|
+
def add(severity, message)
|
63
|
+
severity = TileUpLogger.sym_to_severity(severity)
|
64
|
+
logger.add(severity, message)
|
65
|
+
end
|
66
|
+
|
67
|
+
# is logger in verbose mode?
|
68
|
+
def verbose?
|
69
|
+
@options.verbose
|
70
|
+
end
|
71
|
+
|
72
|
+
# create or return a logger
|
73
|
+
def logger
|
74
|
+
@logger ||= create_logger
|
75
|
+
end
|
76
|
+
|
77
|
+
# subclasses should overwrite this method, creating what ever
|
78
|
+
# logger they want to
|
79
|
+
def create_logger
|
80
|
+
raise "You should create your own `create_logger` method"
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
# Log to console logger
|
86
|
+
class ConsoleLogger < TileUpLogger
|
87
|
+
private
|
88
|
+
def create_logger
|
89
|
+
@logger = Logger.new(STDOUT)
|
90
|
+
@logger.formatter = Proc.new do |sev, time, prg, msg|
|
91
|
+
"#{time.strftime('%H:%M:%S').to_s} => #{msg}\n"
|
92
|
+
end
|
93
|
+
@logger
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/tileup/tiler.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'RMagick'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'tileup/logger'
|
5
|
+
|
6
|
+
module TileUp
|
7
|
+
|
8
|
+
class Tiler
|
9
|
+
|
10
|
+
def initialize(image_filename, options)
|
11
|
+
default_options = {
|
12
|
+
auto_zoom_levels: nil,
|
13
|
+
tile_width: 256,
|
14
|
+
tile_height: 256,
|
15
|
+
filename_prefix: "map_tile",
|
16
|
+
output_dir: ".",
|
17
|
+
extend_incomplete_tiles: true,
|
18
|
+
verbose: false
|
19
|
+
}
|
20
|
+
@options = OpenStruct.new(default_options.merge(options))
|
21
|
+
@options.tile_width = @options.tile_width.to_i unless !@options.tile_width.respond_to? :to_i
|
22
|
+
@options.tile_height = @options.tile_height.to_i unless !@options.tile_height.respond_to? :to_i
|
23
|
+
@extension = image_filename.split(".").last
|
24
|
+
@filename_prefix = @options.filename_prefix
|
25
|
+
@logger = ConsoleLogger.new(:info, {verbose: @options.verbose})
|
26
|
+
|
27
|
+
begin
|
28
|
+
@image = Magick::Image::read(image_filename).first
|
29
|
+
rescue Magick::ImageMagickError => e
|
30
|
+
@logger.error "Could not open image #{image_filename}."
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
|
34
|
+
if @options.auto_zoom_levels && @options.auto_zoom_levels > 20
|
35
|
+
@logger.warn "Warning: auto zoom levels hard limited to 20."
|
36
|
+
@options.auto_zoom_levels = 20
|
37
|
+
end
|
38
|
+
if @options.auto_zoom_levels && @options.auto_zoom_levels <= 0
|
39
|
+
@options.auto_zoom_levels = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
@logger.info "Opened #{image_filename}, #{@image.columns} x #{@image.rows}"
|
43
|
+
|
44
|
+
# pre-process our inputs to work out what we're supposed to do
|
45
|
+
tasks = []
|
46
|
+
|
47
|
+
if @options.auto_zoom_levels.nil?
|
48
|
+
# if we have no auto zoom request, then
|
49
|
+
# we dont shrink or scale, and save directly to the output
|
50
|
+
# dir.
|
51
|
+
tasks << {
|
52
|
+
output_dir: @options.output_dir, # normal output dir
|
53
|
+
scale: 1.0 # dont scale
|
54
|
+
}
|
55
|
+
else
|
56
|
+
# do have zoom levels, so construct those tasks
|
57
|
+
zoom_name = 20
|
58
|
+
scale = 1.0
|
59
|
+
tasks << {
|
60
|
+
output_dir: File.join(@options.output_dir, zoom_name.to_s),
|
61
|
+
scale: scale
|
62
|
+
}
|
63
|
+
(@options.auto_zoom_levels-1).times do |level|
|
64
|
+
scale = scale / 2.0
|
65
|
+
zoom_name = zoom_name - 1
|
66
|
+
tasks << {
|
67
|
+
output_dir: File.join(@options.output_dir, zoom_name.to_s),
|
68
|
+
scale: scale
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# run through tasks list
|
74
|
+
tasks.each do |task|
|
75
|
+
image = @image
|
76
|
+
image_path = File.join(task[:output_dir], @filename_prefix)
|
77
|
+
if task[:scale] != 1.0
|
78
|
+
# if scale required, scale image
|
79
|
+
begin
|
80
|
+
image = @image.scale(task[:scale])
|
81
|
+
rescue RuntimeError => e
|
82
|
+
message = "Failed to scale image, are you sure the original image "\
|
83
|
+
"is large enough to scale down this far (#{scale}) with this "\
|
84
|
+
"tilesize (#{@options.tile_width}x#{@options.tile_height})?"
|
85
|
+
@logger.error message
|
86
|
+
exit
|
87
|
+
end
|
88
|
+
end
|
89
|
+
# make output dir
|
90
|
+
make_path(task[:output_dir])
|
91
|
+
self.make_tiles(image, image_path, @options.tile_width, @options.tile_height)
|
92
|
+
image = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
@logger.info "Finished."
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def make_path(directory_path)
|
100
|
+
FileUtils.mkdir_p directory_path
|
101
|
+
end
|
102
|
+
|
103
|
+
def make_tiles(image, filename_prefix, tile_width, tile_height)
|
104
|
+
# find image width and height
|
105
|
+
# then find out how many tiles we'll get out of
|
106
|
+
# the image, then use that for the xy offset in crop.
|
107
|
+
num_columns = (image.columns/tile_width.to_f).ceil
|
108
|
+
num_rows = (image.rows/tile_height.to_f).ceil
|
109
|
+
x,y,column,row = 0,0,0,0
|
110
|
+
crops = []
|
111
|
+
|
112
|
+
@logger.info "Tiling image into columns: #{num_columns}, rows: #{num_rows}"
|
113
|
+
|
114
|
+
while true
|
115
|
+
x = column * tile_width
|
116
|
+
y = row * tile_height
|
117
|
+
crops << {
|
118
|
+
x: x,
|
119
|
+
y: y,
|
120
|
+
row: row,
|
121
|
+
column: column
|
122
|
+
}
|
123
|
+
column = column + 1
|
124
|
+
if column >= num_columns
|
125
|
+
column = 0
|
126
|
+
row = row + 1
|
127
|
+
end
|
128
|
+
if row >= num_rows
|
129
|
+
break
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
crops.each do |c|
|
134
|
+
@logger.verbose "Crop: x: #{c[:x]}, y: #{c[:y]}, w: #{tile_width}, h: #{tile_height}"
|
135
|
+
ci = image.crop(c[:x], c[:y], tile_width, tile_height, true);
|
136
|
+
|
137
|
+
# unless told to do otherwise, extend tiles in the last row and column
|
138
|
+
# if they do not fill an entire tile width and height.
|
139
|
+
|
140
|
+
is_edge = (c[:row] == num_rows - 1 || c[:column] == num_columns - 1)
|
141
|
+
needs_extension = ci.rows != tile_height || ci.columns != tile_width
|
142
|
+
if @options.extend_incomplete_tiles && is_edge && needs_extension
|
143
|
+
# defaults to white background color, but transparent is probably
|
144
|
+
# a better default for our purposes.
|
145
|
+
ci.background_color = "none"
|
146
|
+
# fill to width height, start from top left corner.
|
147
|
+
ci = ci.extent(tile_width, tile_height, 0, 0)
|
148
|
+
end
|
149
|
+
|
150
|
+
@logger.verbose "Saving tile: #{c[:row]}, #{c[:column]}..."
|
151
|
+
ci.write("#{filename_prefix}_#{c[:column]}_#{c[:row]}.#{@extension}")
|
152
|
+
@logger.verbose "Saving tile: #{c[:row]}, #{c[:column]}... saved"
|
153
|
+
|
154
|
+
ci = nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
data/tileup.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tileup/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'tileup'
|
8
|
+
spec.version = TileUp::VERSION
|
9
|
+
spec.date = Date.today.to_s
|
10
|
+
spec.summary = "Turn an image into an X,Y tile set for use with JS mapping libraries"
|
11
|
+
spec.description = spec.summary
|
12
|
+
spec.authors = ["Oliver Marriott"]
|
13
|
+
spec.email = 'hello@omarriott.com'
|
14
|
+
spec.homepage = 'http://github.com/rktjmp/tileup'
|
15
|
+
spec.license = "MIT"
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
spec.add_runtime_dependency "rmagick", ["~> 2.13.2"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tileup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rmagick
|
@@ -27,6 +27,38 @@ dependencies:
|
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 2.13.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
30
62
|
description: Turn an image into an X,Y tile set for use with JS mapping libraries
|
31
63
|
email: hello@omarriott.com
|
32
64
|
executables:
|
@@ -34,10 +66,18 @@ executables:
|
|
34
66
|
extensions: []
|
35
67
|
extra_rdoc_files: []
|
36
68
|
files:
|
37
|
-
-
|
69
|
+
- CHANGES.md
|
70
|
+
- LICENCE.txt
|
71
|
+
- README.md
|
38
72
|
- bin/tileup
|
73
|
+
- lib/tileup.rb
|
74
|
+
- lib/tileup/logger.rb
|
75
|
+
- lib/tileup/tiler.rb
|
76
|
+
- lib/tileup/version.rb
|
77
|
+
- tileup.gemspec
|
39
78
|
homepage: http://github.com/rktjmp/tileup
|
40
|
-
licenses:
|
79
|
+
licenses:
|
80
|
+
- MIT
|
41
81
|
post_install_message:
|
42
82
|
rdoc_options: []
|
43
83
|
require_paths:
|
@@ -61,3 +101,4 @@ signing_key:
|
|
61
101
|
specification_version: 3
|
62
102
|
summary: Turn an image into an X,Y tile set for use with JS mapping libraries
|
63
103
|
test_files: []
|
104
|
+
has_rdoc:
|