Permalink
Browse files

Added MBTiles output option for tilestache-seed

  • Loading branch information...
1 parent 5cb19cf commit 277a592d376e7f2da38e15880cf42fa8c5c09d34 @migurski migurski committed Jul 4, 2011
Showing with 77 additions and 10 deletions.
  1. +49 −0 TileStache/MBTiles.py
  2. +3 −0 man/tilestache-seed.1
  3. +25 −10 scripts/tilestache-seed.py
View
49 TileStache/MBTiles.py
@@ -100,6 +100,7 @@ def tileset_exists(filename):
# this always works
db = _connect(filename)
+ db.text_factory = bytes
try:
db.execute('SELECT name, value FROM metadata LIMIT 1')
@@ -115,6 +116,7 @@ def get_tile(filename, coord):
If the tile does not exist, None is returned for the content.
"""
db = _connect(filename)
+ db.text_factory = bytes
formats = {'png': 'image/png', 'jpg': 'image/jpeg', None: None}
format = db.execute("SELECT value FROM metadata WHERE name='format'").fetchone()
@@ -128,6 +130,19 @@ def get_tile(filename, coord):
return mime_type, content
+def put_tile(filename, coord, content):
+ """
+ """
+ db = _connect(filename)
+ db.text_factory = bytes
+
+ tile_row = (2**coord.zoom - 1) - coord.row # Hello, Paul Ramsey.
+ q = 'REPLACE INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES (?, ?, ?, ?)'
+ db.execute(q, (coord.zoom, coord.column, tile_row, content))
+
+ db.commit()
+ db.close()
+
class Provider:
""" MBTiles provider.
@@ -170,3 +185,37 @@ def save(self, out, format):
raise Exception('Requested format "%s" does not match tileset format "%s"' % (format, self.format))
out.write(self.content)
+
+class Cache:
+ """ Cache provider for writing to MBTiles files.
+
+ This class is not exposed as a normal cache provider for TileStache,
+ because MBTiles has restrictions on file formats that aren't quite
+ compatible with some of the looser assumptions made by TileStache.
+ Instead, this cache provider is provided for use with the script
+ tilestache-seed.py, which can be called with --to-mbtiles option
+ to write cached tiles to a new tileset.
+ """
+ def __init__(self, filename, format, name):
+ """
+ """
+ self.filename = filename
+
+ if not tileset_exists(filename):
+ create_tileset(filename, name, 'baselayer', '0', '', format.lower())
+
+ def lock(self, layer, coord, format):
+ return
+
+ def unlock(self, layer, coord, format):
+ return
+
+ def read(self, layer, coord, format):
+ """ Return raw tile content from tileset.
+ """
+ return get_tile(self.filename, coord)[1]
+
+ def save(self, body, layer, coord, format):
+ """ Write raw tile content to tileset.
+ """
+ put_tile(self.filename, coord, body)
View
3 man/tilestache-seed.1
@@ -50,6 +50,9 @@ Optional output directory for tiles, to override configured cache with the equiv
More information in http://tilestache.org/doc/#caches.
.TP
+.B \-\-to\-mbtiles
+Optional output file for tiles, will be created as an MBTiles 1.1 tileset. See http://mbtiles.org for more information.
+.TP
.B \-x, \-\-ignore-cached
Re-render every tile, whether it is in the cache already or not.
.SH SEE ALSO
View
35 scripts/tilestache-seed.py
@@ -17,12 +17,9 @@
except ImportError:
from simplejson import dump as json_dump
-from TileStache import parseConfigfile, getTile
-from TileStache.Core import KnownUnknown
-from TileStache.Caches import Disk
-
-from ModestMaps.Core import Coordinate
-from ModestMaps.Geo import Location
+#
+# Most imports can be found below, after the --include-path option is known.
+#
parser = OptionParser(usage="""%prog [options] [zoom...]
@@ -66,6 +63,9 @@
parser.add_option('-d', '--output-directory', dest='outputdirectory',
help='Optional output directory for tiles, to override configured cache with the equivalent of: {"name": "Disk", "path": <output directory>, "dirs": "portable", "gzip": []}. More information in http://tilestache.org/doc/#caches.')
+parser.add_option('--to-mbtiles', dest='mbtiles_output',
+ help='Optional output file for tiles, will be created as an MBTiles 1.1 tileset. See http://mbtiles.org for more information.')
+
parser.add_option('-x', '--ignore-cached', action='store_true', dest='ignore_cached',
help='Re-render every tile, whether it is in the cache already or not.')
@@ -104,10 +104,17 @@ def generateCoordinates(ul, lr, zooms, padding):
options, zooms = parser.parse_args()
if options.include:
-
for p in options.include.split(':'):
path.insert(0, p)
+ from TileStache import parseConfigfile, getTile
+ from TileStache.Core import KnownUnknown
+ from TileStache.Caches import Disk, Multi
+ from TileStache import MBTiles
+
+ from ModestMaps.Core import Coordinate
+ from ModestMaps.Geo import Location
+
try:
if options.config is None:
raise KnownUnknown('Missing required configuration (--config) parameter.')
@@ -116,9 +123,6 @@ def generateCoordinates(ul, lr, zooms, padding):
raise KnownUnknown('Missing required layer (--layer) parameter.')
config = parseConfigfile(options.config)
-
- if options.outputdirectory:
- config.cache = Disk(options.outputdirectory, dirs='portable', gzip=[])
if options.layer not in config.layers:
raise KnownUnknown('"%s" is not a layer I know about. Here are some that I do know about: %s.' % (options.layer, ', '.join(sorted(config.layers.keys()))))
@@ -128,6 +132,17 @@ def generateCoordinates(ul, lr, zooms, padding):
verbose = options.verbose
extension = options.extension
progressfile = options.progressfile
+
+ if options.outputdirectory and options.mbtiles_output:
+ cache1 = Disk(options.outputdirectory, dirs='portable', gzip=[])
+ cache2 = MBTiles.Cache(options.mbtiles_output, extension, options.layer)
+ config.cache = Multi([cache1, cache2])
+
+ elif options.outputdirectory:
+ config.cache = Disk(options.outputdirectory, dirs='portable', gzip=[])
+
+ elif options.mbtiles_output:
+ config.cache = MBTiles.Cache(options.mbtiles_output, extension, options.layer)
lat1, lon1, lat2, lon2 = options.bbox
south, west = min(lat1, lat2), min(lon1, lon2)

0 comments on commit 277a592

Please sign in to comment.