Skip to content

SQLite

MapTile

MapTile(
    x=None,
    y=None,
    z=None,
    filespec=None,
    tile=None,
    suffix="jpg",
)

Bases: object

Parameters:

Name Type Description Default
x int

The X index for this tile

None
y int

The Y index for this tile

None
z int

The Z index for this tile if there is one

None
filespec str

The location of this within the map tile cache

None
tile MapTile

Make a copy of this object

None
suffix str

The image suffix, jpg or png usually

'jpg'

Returns:

Type Description
MapTile

An instance of this object

Source code in osm_merge/fieldwork/sqlite.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def __init__(
    self,
    x: int = None,
    y: int = None,
    z: int = None,
    filespec: str = None,
    tile: "MapTile" = None,
    suffix="jpg",
):
    """This is a simple wrapper around mercantile.tile to associate a
    filespec with the grid coordinates.

    Args:
        x (int): The X index for this tile
        y (int): The Y index for this tile
        z (int): The Z index for this tile if there is one
        filespec (str): The location of this within the map tile cache
        tile (MapTile): Make a copy of this object
        suffix (str): The image suffix, jpg or png usually

    Returns:
        (MapTile): An instance of this object
    """
    if tile:
        self.x = tile.x
        self.y = tile.y
        self.z = tile.z
    else:
        self.x = x
        self.y = y
        self.z = z
    self.blob = None
    self.filespec = None
    if not filespec and self.z:
        self.filespec = f"{self.z}/{self.y}/{self.x}.{suffix}"
    elif filespec:
        self.filespec = filespec
        tmp = filespec.split("/")
        self.z = tmp[0]
        self.x = tmp[2]
        self.y = tmp[1].replace("." + suffix, "")

readImage

readImage(base='./')

Read a map tile out of the disk based map tile cache.

Parameters:

Name Type Description Default
base str

The top level directory for the map tile cache

'./'
Source code in osm_merge/fieldwork/sqlite.py
75
76
77
78
79
80
81
82
83
84
85
86
def readImage(self, base: str = "./"):
    """Read a map tile out of the disk based map tile cache.

    Args:
        base (str): The top level directory for the map tile cache
    """
    file = f"{base}/{self.filespec}"
    logging.debug("Adding tile image: %s" % file)
    if os.path.exists(file):
        size = os.path.getsize(file)
        file = open(file, "rb")
        self.blob = file.read(size)

dump

dump()

Dump internal data structures, for debugging purposes only.

Source code in osm_merge/fieldwork/sqlite.py
88
89
90
91
92
93
94
95
96
97
98
def dump(self):
    """Dump internal data structures, for debugging purposes only."""
    if self.z:
        print("Z: %r" % self.z)
    if self.x:
        print("X: %r" % self.x)
    if self.y:
        print("Y: %r" % self.y)
    print("Filespec: %s" % self.filespec)
    if self.blob:
        print("Tile size is: %d" % len(self.blob))

DataFile

DataFile(dbname=None, suffix='jpg', append=False)

Bases: object

Parameters:

Name Type Description Default
dbname str

The name of the output sqlite file

None
suffix str

The image suffix, jpg or png usually

'jpg'
append bool

Whether to append to or create the database

False

Returns:

Type Description
DataFile

An instance of this class

Source code in osm_merge/fieldwork/sqlite.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def __init__(
    self,
    dbname: str = None,
    suffix: str = "jpg",
    append: bool = False,
):
    """Handle the sqlite3 database file.

    Args:
        dbname (str): The name of the output sqlite file
        suffix (str): The image suffix, jpg or png usually
        append (bool): Whether to append to or create the database

    Returns:
        (DataFile): An instance of this class
    """
    self.db = None
    self.cursor = None
    if dbname:
        self.createDB(dbname, append)
    self.dbname = dbname
    self.metadata = None
    self.toplevel = None
    self.suffix = suffix

addBounds

addBounds(bounds)

Mbtiles has a bounds field, Osmand doesn't.

Parameters:

Name Type Description Default
bounds int

The bounds value for ODK Collect mbtiles

required
Source code in osm_merge/fieldwork/sqlite.py
127
128
129
130
131
132
133
134
135
136
137
138
def addBounds(
    self,
    bounds: tuple[float, float, float, float],
):
    """Mbtiles has a bounds field, Osmand doesn't.

    Args:
        bounds (int): The bounds value for ODK Collect mbtiles
    """
    entry = str(bounds)
    entry = entry[1 : len(entry) - 1].replace(" ", "")
    self.cursor.execute(f"INSERT OR IGNORE INTO metadata (name, value) VALUES('bounds', '{entry}') ")

addZoomLevels

addZoomLevels(zoom_levels)

Mbtiles has a maxzoom and minzoom fields, Osmand doesn't.

Parameters:

Name Type Description Default
zoom_levels list

The zoom levels

required
Source code in osm_merge/fieldwork/sqlite.py
140
141
142
143
144
145
146
147
148
149
150
151
152
def addZoomLevels(
    self,
    zoom_levels: list[int],
):
    """Mbtiles has a maxzoom and minzoom fields, Osmand doesn't.

    Args:
        zoom_levels (list)): The zoom levels
    """
    min_zoom = min(zoom_levels)
    max_zoom = max(zoom_levels)
    self.cursor.execute(f"INSERT OR IGNORE INTO metadata (name, value) VALUES('minzoom', '{min_zoom}') ")
    self.cursor.execute(f"INSERT OR IGNORE INTO metadata (name, value) VALUES('maxzoom', '{max_zoom}') ")

createDB

createDB(dbname, append=False)

Create and sqlitedb in either mbtiles or Osman sqlitedb format.

Parameters:

Name Type Description Default
dbname str

The filespec of the sqlite output file

required
Source code in osm_merge/fieldwork/sqlite.py
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
def createDB(
    self,
    dbname: str,
    append: bool = False,
):
    """Create and sqlitedb in either mbtiles or Osman sqlitedb format.

    Args:
        dbname (str): The filespec of the sqlite output file
    """
    suffix = os.path.splitext(dbname)[1]

    if os.path.exists(dbname) and append == False:
        os.remove(dbname)

    self.db = sqlite3.connect(dbname)
    self.cursor = self.db.cursor()
    self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='tiles'")
    exists = self.cursor.fetchone()
    if exists and append:
        logging.info("Appending to database file %s" % dbname)
        return

    if suffix == ".mbtiles":
        self.cursor.execute("CREATE TABLE tiles (zoom_level integer, tile_column integer, tile_row integer, tile_data blob)")
        self.cursor.execute("CREATE INDEX tiles_idx on tiles (zoom_level, tile_column, tile_row)")
        self.cursor.execute("CREATE TABLE metadata (name text, value text)")
        # These get populated later
        name = dbname
        description = "Created by osm_merge/basemapper.py"
        self.cursor.execute("CREATE UNIQUE INDEX metadata_idx  ON metadata (name)")
        self.cursor.execute("INSERT INTO metadata (name, value) VALUES('version', '1.1')")
        self.cursor.execute("INSERT INTO metadata (name, value) VALUES('type', 'baselayer')")
        self.cursor.execute(f"INSERT INTO metadata (name, value) VALUES('name', '{name}')")
        self.cursor.execute(f"INSERT INTO metadata (name, value) VALUES('description', '{description}')")
        # self.cursor.execute(f"INSERT INTO metadata (name, value) VALUES('bounds', '{bounds}')")
        self.cursor.execute("INSERT INTO metadata (name, value) VALUES('format', 'jpg')")
    if "sqlite" in suffix:
        # s is always 0
        self.cursor.execute("CREATE TABLE tiles (x int, y int, z int, s int, image blob, PRIMARY KEY (x,y,z,s));")
        self.cursor.execute("CREATE INDEX IND on tiles (x,y,z,s)")
        # Info is simple "2|4" for example, it gets populated later
        self.cursor.execute("CREATE TABLE info (maxzoom Int, minzoom Int);")
        # the metadata is the locale as a string
        loc = locale.getlocale()[0]
        self.cursor.execute(f"CREATE TABLE  android_metadata ({loc})")
    self.db.commit()
    logging.info("Created database file %s" % dbname)

writeTiles

writeTiles(tiles, base='./', image_format='jpg')

Write map tiles into the to the map tile cache.

Parameters:

Name Type Description Default
tiles list

The map tiles to write to the map tile cache

required
base str

The default local to write tiles to disk

'./'
Source code in osm_merge/fieldwork/sqlite.py
203
204
205
206
207
208
209
210
211
212
213
214
def writeTiles(self, tiles: list, base: str = "./", image_format: str = "jpg"):
    """Write map tiles into the to the map tile cache.

    Args:
        tiles (list): The map tiles to write to the map tile cache
        base (str): The default local to write tiles to disk
    """
    for tile in tiles:
        xyz = MapTile(tile=tile, suffix=image_format)
        xyz.readImage(base)
        # xyz.dump()
        self.writeTile(xyz)

writeTile

writeTile(tile)

Write a map tile into the sqlite database file.

Parameters:

Name Type Description Default
tile MapTile

The map tile to write to the file

required
Source code in osm_merge/fieldwork/sqlite.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
def writeTile(
    self,
    tile: MapTile,
):
    """Write a map tile into the sqlite database file.

    Args:
        tile (MapTile): The map tile to write to the file
    """
    if tile.blob is None:
        logging.error(f"Map tile {tile.filespec} has no image data!")
        # tile.dump()
        return False

    suffix = os.path.splitext(self.dbname)[1]

    if "sqlite" in suffix:
        # Osmand tops out at zoom level 16, so the real zoom level is inverse,
        # and can go negative for really high zoom levels.
        z = 17 - tile.z
        self.db.execute(
            "INSERT INTO tiles (x, y, z, s, image) VALUES (?, ?, ?, ?, ?)",
            [tile.x, tile.y, z, 0, sqlite3.Binary(tile.blob)],
        )

    if suffix == ".mbtiles":
        y = (1 << tile.z) - tile.y - 1
        self.db.execute(
            "INSERT INTO tiles (tile_row, tile_column, zoom_level, tile_data) VALUES (?, ?, ?, ?)",
            [y, tile.x, tile.z, sqlite3.Binary(tile.blob)],
        )

    self.db.commit()

options: show_source: false heading_level: 3