Skip to content

Instantly share code, notes, and snippets.

@martinsik
Last active July 9, 2018 09:17
Show Gist options
  • Save martinsik/4523934 to your computer and use it in GitHub Desktop.
Save martinsik/4523934 to your computer and use it in GitHub Desktop.
Source codes for tutorial on Creating .mbtiles DB for iOS MapBox from hi-res map image http://martinsikora.com/creating-mbtiles-db-for-ios-mapbox-from-hi-res-map-image
import sqlite3
import os
import glob
import sys
from pprint import pprint
if len(sys.argv) == 1 or sys.argv[1] in ['-h', '--help', 'help', '/?']:
print "Usage: python create_mbtiles.py mbtiles_output_db"
quit()
db_name = sys.argv[1]
# probably all mbtiles DBs use 256x256 tile size
tile_size = 256
# remove old mbtiles db if it exists
if os.path.isfile(db_name):
os.remove(db_name)
conn = sqlite3.connect(db_name)
c = conn.cursor()
# create database schema
c.execute('CREATE TABLE metadata (name text, value text)')
c.execute('CREATE TABLE tiles (zoom_level integer, tile_column integer, tile_row integer, tile_data blob)')
# indicies aren't necessary but for large databases with many zoom levels may increase performance
c.execute('CREATE UNIQUE INDEX tile_index ON tiles (zoom_level, tile_column, tile_row)')
c.execute('CREATE UNIQUE INDEX name ON metadata (name)')
# fill metadata table with some basic info
c.execute("INSERT INTO metadata VALUES ('name', 'my_mbtiles_db')")
c.execute("INSERT INTO metadata VALUES ('type', 'baselayer')")
c.execute("INSERT INTO metadata VALUES ('version', '1.0')")
c.execute("INSERT INTO metadata VALUES ('description', '')")
c.execute("INSERT INTO metadata VALUES ('format', 'jpg')")
# start at zoom level 0
z = 0
# which tile sizes we want to use
for size in [256, 512, 1024, 2048]:
tilesPerRow = size / tile_size
# tilesPerRow ^ 2 is number of tileXXX.jpg we will process for this zoom level
for i in range(0, pow(tilesPerRow, 2)):
y = i / tilesPerRow
x = i % tilesPerRow
image = 'tiles' + str(size) + '/tile%03d.jpg' % (y * tilesPerRow + x)
# load image and add it to the database
with open(image, 'rb') as f:
ablob = f.read()
# that "tilesPerRow - y - 1" expression is to get y position from bottom, not top
c.execute("INSERT INTO tiles VALUES (?, ?, ?, ?)", [ z, x, tilesPerRow - y - 1, buffer(ablob)])
z += 1
conn.commit()
conn.close()
import sys
import sqlite3
import os
import json
# print help?
if len(sys.argv) == 1 or sys.argv[1] in ['-h', '--help', 'help', '/?']:
print "Usage: python extract.py mbtiles_file_name"
quit()
mbtiles_file = sys.argv[1]
# make sure file exist
try:
with open(mbtiles_file) as f: pass
except IOError as e:
print "File '%s' doesn't exists" % mbtiles_file
quit()
# open sqlite3 database
conn = sqlite3.connect(mbtiles_file)
# get tile format from metadata table
format_row = conn.execute('SELECT value FROM metadata WHERE name = ?', ['format']).fetchone()
if format_row:
format = format_row[0]
else:
format = 'png' # default is png
# get map name (root dir for extracted tiles)
dir_root = mbtiles_file[:mbtiles_file.rfind('.')]
if not os.path.exists(dir_root):
os.makedirs(dir_root)
# dump all metadata as json
metadata_dict = { }
for row in conn.execute('SELECT name, value FROM metadata'):
metadata_dict[row[0]] = row[1]
f = open(dir_root + '/metadata.json', 'w+')
json.dump(metadata_dict, f)
# fetch all tile rows
for row in conn.execute('SELECT zoom_level, tile_row, tile_column, tile_data FROM tiles ORDER BY zoom_level, tile_row, tile_column'):
# create directory if it doesn't already exist
dir_name = dir_root + '/' + str(row[0])
if not os.path.exists(dir_name):
os.makedirs(dir_name)
# tile_name = str(row[1]) + '_' + str(row[2]) +
tile_name = '%d_%d.%s' % (row[1], row[2], format)
# dump tile data (png or jpg image)
f = open(dir_name + '/' + tile_name, 'w+')
f.write(row[3])
#!/bin/bash
SIZES=("512" "1024" "2048")
for i in ${!SIZES[*]}
do
SIZE=${SIZES[$i]}
echo $SIZE
# first, resize original image
convert -resize $SIZE"x"$SIZE! chernarus2048.jpg chernarus$SIZE"x"$SIZE.jpg
mkdir tiles$SIZE
# slice resized image into 256x256 tiles
convert -crop 256x256 chernarus$SIZE"x"$SIZE.jpg tiles$SIZE/tile%04d.jpg
rm chernarus$SIZE"x"$SIZE.jpg
done
#import "ViewController.h"
#import "MapBox.h"
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
RMMBTilesSource *offlineSource = [[RMMBTilesSource alloc] initWithTileSetURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"chernarus" ofType:@"mbtiles"]]];
RMMapView *mapView = [[RMMapView alloc] initWithFrame:self.view.bounds andTilesource:offlineSource];
// default zoom
mapView.zoom = 2;
// hard code minimal zoom. Try to run in without it to see what happens.
mapView.minZoom = 1;
// hide MapBox logo
mapView.showLogoBug = NO;
// hide bottom right "i" icon
[mapView setHideAttribution:YES];
mapView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
mapView.adjustTilesForRetinaDisplay = YES; // these tiles aren't designed specifically for retina, so make them legible
[self.view addSubview:mapView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment