Ejemplo n.º 1
0
def tilejson(map_path, layer):
    try:
        mbtiles = os.path.join(
            maps_root, map_path,
            '{}.mbtiles'.format(layer if layer else 'index'))
        reader = MBTilesReader(mbtiles)
        metadata = reader.metadata()
        tilejson = {}
        tilejson['tilejson'] = '2.2.0'
        if 'id' in metadata:
            tilejson['id'] = metadata['id']
        tilejson['bounds'] = [float(x) for x in metadata['bounds'].split(',')]
        tilejson['center'] = [float(x) for x in metadata['center'].split(',')
                              ]  ## Ignored ??
        tilejson['maxzoom'] = int(metadata['maxzoom'])
        tilejson['minzoom'] = int(metadata['minzoom'])
        tilejson['format'] = 'pbf'
        tilejson['scheme'] = 'xyz'
        tilejson['tiles'] = [
            server_url('{}{}/mvtiles/{{z}}/{{x}}/{{y}}'.format(
                map_path, '/{}'.format(layer) if layer else ''))
        ]
        tilejson['vector_layers'] = json.loads(
            metadata['json'])['vector_layers']
        return response.json(tilejson)
    except ExtractionError:
        pass
    except (InvalidFormatError, sqlite3.OperationalError):
        exceptions.abort(404, 'Cannot read tile database')
    return response.empty(status=204)
Ejemplo n.º 2
0
def maps():
    flatmap_list = []
    for tile_dir in pathlib.Path(root_paths['flatmaps']).iterdir():
        mbtiles = os.path.join(root_paths['flatmaps'], tile_dir,
                               'index.mbtiles')
        if os.path.isdir(tile_dir) and os.path.exists(mbtiles):
            reader = MBTilesReader(mbtiles)
            try:
                source_row = reader._query(
                    "SELECT value FROM metadata WHERE name='source';"
                ).fetchone()
            except (InvalidFormatError, sqlite3.OperationalError):
                flask.abort(404,
                            'Cannot read tile database: {}'.format(mbtiles))
            if source_row is not None:
                flatmap = {'id': tile_dir.name, 'source': source_row[0]}
                created = reader._query(
                    "SELECT value FROM metadata WHERE name='created';"
                ).fetchone()
                if created is not None:
                    flatmap['created'] = created[0]
                describes = reader._query(
                    "SELECT value FROM metadata WHERE name='describes';"
                ).fetchone()
                if describes is not None and describes[0]:
                    flatmap['describes'] = normalise_identifier(describes[0])
                flatmap_list.append(flatmap)
    return flask.jsonify(flatmap_list)
Ejemplo n.º 3
0
class TileDatabase(object):
    def __init__(self, db_file):
        self._db = MBTilesReader(db_file)

    def execute(self, sql):
        return self._db._query(sql)

    def metadata(self):
        return self._db.metadata()
Ejemplo n.º 4
0
def get_metadata(map_path, name):
    mbtiles = os.path.join(root_paths['flatmaps'], map_path, 'index.mbtiles')
    reader = MBTilesReader(mbtiles)
    try:
        row = reader._query(
            "SELECT value FROM metadata WHERE name='{}';".format(
                name)).fetchone()
    except (InvalidFormatError, sqlite3.OperationalError):
        flask.abort(404, 'Cannot read tile database')
    return {} if row is None else json.loads(row[0])
Ejemplo n.º 5
0
def image_tiles(request, map_path, layer, z, y, x):
    try:
        mbtiles = os.path.join(maps_root, map_path, '{}.mbtiles'.format(layer))
        reader = MBTilesReader(mbtiles)
        return response.raw(reader.tile(int(z), int(y), int(x)),
                            headers={'Content-Type': 'image/png'})
    except ExtractionError:
        pass
    except (InvalidFormatError, sqlite3.OperationalError):
        exceptions.abort(404, 'Cannot read tile database')
    return response.raw(blank_tile(), headers={'Content-Type': 'image/png'})
Ejemplo n.º 6
0
def vector_tiles(map_path, z, y, x):
    try:
        mbtiles = os.path.join(root_paths['flatmaps'], map_path,
                               'index.mbtiles')
        reader = MBTilesReader(mbtiles)
        return flask.send_file(io.BytesIO(reader.tile(z, x, y)),
                               mimetype='application/octet-stream')
    except ExtractionError:
        pass
    except (InvalidFormatError, sqlite3.OperationalError):
        flask.abort(404, 'Cannot read tile database')
    return flask.make_response('', 204)
Ejemplo n.º 7
0
def image_tiles(map_path, layer, z, y, x):
    try:
        mbtiles = os.path.join(root_paths['flatmaps'], map_path,
                               '{}.mbtiles'.format(layer))
        reader = MBTilesReader(mbtiles)
        return flask.send_file(io.BytesIO(reader.tile(z, x, y)),
                               mimetype='image/png')
    except ExtractionError:
        pass
    except (InvalidFormatError, sqlite3.OperationalError):
        flask.abort(404, 'Cannot read tile database')
    return flask.send_file(blank_tile(), mimetype='image/png')
Ejemplo n.º 8
0
def image_tiles(map_id, layer, z, y, x):
    try:
        mbtiles = os.path.join(settings['FLATMAP_ROOT'], map_id,
                               '{}.mbtiles'.format(layer))
        reader = MBTilesReader(mbtiles)
        image_bytes = io.BytesIO(reader.tile(z, x, y))
        return send_bytes(image_bytes, 'image/png')
    except ExtractionError:
        pass
    except (InvalidFormatError, sqlite3.OperationalError):
        flask.abort(404, 'Cannot read tile database')
    return send_bytes(blank_tile(), 'image/png')
Ejemplo n.º 9
0
def vector_tiles(map_id, z, y, x):
    try:
        mbtiles = os.path.join(settings['FLATMAP_ROOT'], map_id,
                               'index.mbtiles')
        tile_reader = MBTilesReader(mbtiles)
        tile_bytes = tile_reader.tile(z, x, y)
        if metadata(tile_reader, 'compressed'):
            tile_bytes = gzip.decompress(tile_bytes)
        return send_bytes(io.BytesIO(tile_bytes), 'application/octet-stream')
    except ExtractionError:
        pass
    except (InvalidFormatError, sqlite3.OperationalError):
        flask.abort(404, 'Cannot read tile database')
    return flask.make_response('', 204)
Ejemplo n.º 10
0
def vector_tiles(map_path, layer, z, y, x):
    try:
        mbtiles = os.path.join(maps_root, map_path, 'index.mbtiles')
        reader = MBTilesReader(mbtiles)
        tile = reader.tile(z, x, y)
        headers = {'Content-Type': 'application/x-protobuf'}
        if tile[0:2] == b'\x1f\x8b':
            headers['Content-Encoding'] = 'gzip'
        return response.raw(tile, headers=headers)
    except ExtractionError:
        pass
    except (InvalidFormatError, sqlite3.OperationalError):
        exceptions.abort(404, 'Cannot read tile database')
    return response.empty(status=204)
Ejemplo n.º 11
0
 def __init__(self, name):
     """
     Load a MBTile file.
     If `name` is a valid filepath, it will load it. 
     Else, it will attempt to load it within `settings.MBTILES_ROOT` folder.
     """
     mbtiles_file = name
     if not os.path.exists(mbtiles_file):
         if not os.path.exists(app_settings.MBTILES_ROOT):
             raise MBTilesFolderError()
         mbtiles_file = os.path.join(app_settings.MBTILES_ROOT, name)
         if not os.path.exists(mbtiles_file):
             mbtiles_file = "%s.%s" % (mbtiles_file, app_settings.MBTILES_EXT)
             if not os.path.exists(mbtiles_file):
                 raise MBTilesNotFoundError(_("'%s' not found") % mbtiles_file)
     self.fullpath = mbtiles_file
     self.basename = os.path.basename(self.fullpath)
     self._reader = MBTilesReader(self.fullpath, tilesize=app_settings.TILE_SIZE)
Ejemplo n.º 12
0
def maps():
    """
    Get a list of available flatmaps.

    :>jsonarr string id: the flatmap's unique identifier on the server
    :>jsonarr string source: the map's source URL
    :>jsonarr string created: when the map was generated
    :>jsonarr string describes: the map's description
    """
    flatmap_list = []
    root_path = pathlib.Path(settings['FLATMAP_ROOT'])
    if root_path.is_dir():
        for tile_dir in root_path.iterdir():
            mbtiles = os.path.join(settings['FLATMAP_ROOT'], tile_dir,
                                   'index.mbtiles')
            if os.path.isdir(tile_dir) and os.path.exists(mbtiles):
                reader = MBTilesReader(mbtiles)
                try:
                    source_row = reader._query(
                        "SELECT value FROM metadata WHERE name='source';"
                    ).fetchone()
                except (InvalidFormatError, sqlite3.OperationalError):
                    flask.abort(
                        404, 'Cannot read tile database: {}'.format(mbtiles))
                if source_row is not None:
                    flatmap = {'id': tile_dir.name, 'source': source_row[0]}
                    created = reader._query(
                        "SELECT value FROM metadata WHERE name='created';"
                    ).fetchone()
                    if created is not None:
                        flatmap['created'] = created[0]
                    describes = reader._query(
                        "SELECT value FROM metadata WHERE name='describes';"
                    ).fetchone()
                    if describes is not None and describes[0]:
                        flatmap['describes'] = normalise_identifier(
                            describes[0])
                    flatmap_list.append(flatmap)
    return flask.jsonify(flatmap_list)
Ejemplo n.º 13
0
 def load_mbtiles(self, mbtiles):
     """
     Loads all the downloaded *.mbtiles, but centers on the requested one.
     """
     mbt_merge_manager = MbtMergeManager()
     not_merged_mbtiles = mbt_merge_manager.not_merged()
     main_mbtiles_path = App.get_running_app().main_mbtiles_path
     # not yet merged *.mbtiles plus main one
     mbtiles_paths = not_merged_mbtiles + [main_mbtiles_path]
     # requested mbtiles path
     mbtiles_path = os.path.join(App.get_running_app().mbtiles_directory,
                                 mbtiles)
     map_source = MBTilesCompositeMapSource(mbtiles_paths)
     self.map_source = map_source
     mbreader = MBTilesReader(mbtiles_path)
     # centers on requested loaded mbtiles
     metadata = mbreader.metadata()
     if "center" in metadata:
         center = metadata["center"]
         longitude, latitude, default_zoom = map(float, center.split(","))
     # defaults to the minimum available zoom
     zoom = int(default_zoom)
     self.animated_center_on(latitude, longitude, zoom)
Ejemplo n.º 14
0
 def load_mbtiles(self, mbtiles):
     """
     Loads all the downloaded *.mbtiles, but centers on the requested one.
     """
     mbt_merge_manager = MbtMergeManager()
     not_merged_mbtiles = mbt_merge_manager.not_merged()
     main_mbtiles_path = App.get_running_app().main_mbtiles_path
     # not yet merged *.mbtiles plus main one
     mbtiles_paths = not_merged_mbtiles + [main_mbtiles_path]
     # requested mbtiles path
     mbtiles_path = os.path.join(
         App.get_running_app().mbtiles_directory, mbtiles)
     map_source = MBTilesCompositeMapSource(mbtiles_paths)
     self.map_source = map_source
     mbreader = MBTilesReader(mbtiles_path)
     # centers on requested loaded mbtiles
     metadata = mbreader.metadata()
     if "center" in metadata:
         center = metadata["center"]
         longitude, latitude, default_zoom = map(float, center.split(","))
     # defaults to the minimum available zoom
     zoom = int(default_zoom)
     self.animated_center_on(latitude, longitude, zoom)
Ejemplo n.º 15
0
 def __init__(self, name, catalog=None):
     self.catalog = catalog
     self.fullpath = self.objects.fullpath(name, catalog)
     self.basename = os.path.basename(self.fullpath)
     self._reader = MBTilesReader(self.fullpath, tilesize=app_settings.TILE_SIZE)
Ejemplo n.º 16
0
class MBTiles(object):
    """ Represent a MBTiles file """

    objects = MBTilesManager()

    def __init__(self, name):
        """
        Load a MBTile file.
        If `name` is a valid filepath, it will load it. 
        Else, it will attempt to load it within `settings.MBTILES_ROOT` folder.
        """
        mbtiles_file = name
        if not os.path.exists(mbtiles_file):
            if not os.path.exists(app_settings.MBTILES_ROOT):
                raise MBTilesFolderError()
            mbtiles_file = os.path.join(app_settings.MBTILES_ROOT, name)
            if not os.path.exists(mbtiles_file):
                mbtiles_file = "%s.%s" % (mbtiles_file, app_settings.MBTILES_EXT)
                if not os.path.exists(mbtiles_file):
                    raise MBTilesNotFoundError(_("'%s' not found") % mbtiles_file)
        self.fullpath = mbtiles_file
        self.basename = os.path.basename(self.fullpath)
        self._reader = MBTilesReader(self.fullpath, tilesize=app_settings.TILE_SIZE)

    @property
    def id(self):
        iD, ext = os.path.splitext(self.basename)
        return iD

    @property
    def name(self):
        return self.metadata.get('name', self.id)

    @property
    def filesize(self):
        return os.path.getsize(self.fullpath)

    @reify
    def metadata(self):
        return self._reader.metadata()

    @reify
    def bounds(self):
        bounds = self.metadata.get('bounds', '').split(',')
        if len(bounds) != 4:
            logger.warning(_("Invalid bounds metadata in '%s', fallback to whole world.") % self.name)
            bounds = [-180,-90,180,90]
        return tuple(map(float, bounds))

    @reify
    def center(self):
        """
        Return the center (x,y) of the map at this zoom level.
        """
        center = self.metadata.get('center', '').split(',')
        if len(center) == 3:
            lon, lat, zoom = map(float, center)
            zoom = int(zoom)
            if zoom not in self.zoomlevels:
                logger.warning(_("Invalid zoom level (%s), fallback to middle zoom (%s)") % (zoom, self.middlezoom))
                zoom = self.middlezoom
            return (lon, lat, zoom)
        # Invalid center from metadata, guess center from bounds
        lat = self.bounds[1] + (self.bounds[3] - self.bounds[1])/2
        lon = self.bounds[0] + (self.bounds[2] - self.bounds[0])/2
        return (lon, lat, self.middlezoom)

    @property
    def minzoom(self):
        z = self.metadata.get('minzoom', self.zoomlevels[0])
        return int(z)

    @property
    def maxzoom(self):
        z = self.metadata.get('maxzoom', self.zoomlevels[-1])
        return int(z)

    @property
    def middlezoom(self):
        return self.zoomlevels[len(self.zoomlevels)/2]

    @reify
    def zoomlevels(self):
        return self._reader.zoomlevels()

    def tile(self, z, x, y):
        try:
            return self._reader.tile(z, x, y)
        except ExtractionError:
            raise MissingTileError

    def center_tile(self):
        lon, lat, zoom = self.center
        proj = GoogleProjection(app_settings.TILE_SIZE, [zoom])
        return proj.tile_at(zoom, (lon, lat))

    def grid(self, z, x, y, callback=None):
        try:
            return self._reader.grid(z, x, y, callback)
        except ExtractionError:
            raise MissingTileError

    def jsonp(self, request, callback):
        # Raw metadata
        jsonp = dict(self.metadata)
        # Post-processed metadata
        jsonp.update(**{
            "bounds": self.bounds,
            "center": self.center,
            "minzoom": self.minzoom,
            "maxzoom": self.maxzoom,
        })
        # Additionnal info
        tilepattern = reverse("mbtilesmap:tile", kwargs=dict(name=self.id, x='{x}',y='{y}',z='{z}'))
        tilepattern = request.build_absolute_uri(tilepattern)
        tilepattern = tilepattern.replace('%7B', '{').replace('%7D', '}')
        jsonp.update(**{
            "id": self.id,
            "name": self.name,
            "scheme": "xyz",
            "basename": self.basename,
            "filesize": self.filesize,
            "tiles": [tilepattern],
        })
        return '%s(%s);' % (callback, json.dumps(jsonp))
Ejemplo n.º 17
0
class MBTiles(object):
    """ Represent a MBTiles file """

    objects = MBTilesManager()

    def __init__(self, name, catalog=None):
        self.catalog = catalog
        self.fullpath = self.objects.fullpath(name, catalog)
        self.basename = os.path.basename(self.fullpath)
        self._reader = MBTilesReader(self.fullpath, tilesize=app_settings.TILE_SIZE)

    @property
    def id(self):
        iD, ext = os.path.splitext(self.basename)
        return iD

    @property
    def name(self):
        return self.metadata.get('name', self.id)

    @property
    def filesize(self):
        return os.path.getsize(self.fullpath)

    @reify
    def metadata(self):
        return self._reader.metadata()

    @reify
    def bounds(self):
        bounds = self.metadata.get('bounds', '').split(',')
        if len(bounds) != 4:
            logger.warning(_("Invalid bounds metadata in '%s', fallback to whole world.") % self.name)
            bounds = [-180,-90,180,90]
        return tuple(map(float, bounds))

    @reify
    def center(self):
        """
        Return the center (x,y) of the map at this zoom level.
        """
        center = self.metadata.get('center', '').split(',')
        if len(center) == 3:
            lon, lat, zoom = map(float, center)
            zoom = int(zoom)
            if zoom not in self.zoomlevels:
                logger.warning(_("Invalid zoom level (%s), fallback to middle zoom (%s)") % (zoom, self.middlezoom))
                zoom = self.middlezoom
            return (lon, lat, zoom)
        # Invalid center from metadata, guess center from bounds
        lat = self.bounds[1] + (self.bounds[3] - self.bounds[1])/2
        lon = self.bounds[0] + (self.bounds[2] - self.bounds[0])/2
        return (lon, lat, self.middlezoom)

    @property
    def minzoom(self):
        z = self.metadata.get('minzoom', self.zoomlevels[0])
        return int(z)

    @property
    def maxzoom(self):
        z = self.metadata.get('maxzoom', self.zoomlevels[-1])
        return int(z)

    @property
    def middlezoom(self):
        return self.zoomlevels[len(self.zoomlevels)/2]

    @reify
    def zoomlevels(self):
        return self._reader.zoomlevels()

    def tile(self, z, x, y):
        try:
            return self._reader.tile(z, x, y)
        except ExtractionError:
            raise MissingTileError

    def center_tile(self):
        lon, lat, zoom = self.center
        proj = GoogleProjection(app_settings.TILE_SIZE, [zoom])
        return proj.tile_at(zoom, (lon, lat))

    def grid(self, z, x, y, callback=None):
        try:
            return self._reader.grid(z, x, y, callback)
        except ExtractionError:
            raise MissingTileError

    def tilejson(self, request):
        # Raw metadata
        jsonp = dict(self.metadata)
        # Post-processed metadata
        jsonp.update(**{
            "bounds": self.bounds,
            "center": self.center,
            "minzoom": self.minzoom,
            "maxzoom": self.maxzoom,
        })
        # Additionnal info
        try:
            kwargs = dict(name=self.id, x='{x}',y='{y}',z='{z}')
            if self.catalog:
                kwargs['catalog'] = self.catalog
            tilepattern = reverse("mbtilesmap:tile", kwargs=kwargs)
            gridpattern = reverse("mbtilesmap:grid", kwargs=kwargs)
        except NoReverseMatch:
            # In case django-mbtiles was not registered in namespace mbtilesmap
            tilepattern = reverse("tile", kwargs=dict(name=self.id, x='{x}',y='{y}',z='{z}'))
            gridpattern = reverse("grid", kwargs=dict(name=self.id, x='{x}',y='{y}',z='{z}'))
        tilepattern = request.build_absolute_uri(tilepattern)
        gridpattern = request.build_absolute_uri(gridpattern)
        tilepattern = tilepattern.replace('%7B', '{').replace('%7D', '}')
        gridpattern = gridpattern.replace('%7B', '{').replace('%7D', '}')
        jsonp.update(**{
            "tilejson": "2.0.1",
            "id": self.id,
            "name": self.name,
            "scheme": "xyz",
            "basename": self.basename,
            "filesize": self.filesize,
            "tiles": [tilepattern],
            "grids": [gridpattern]
        })
        return json.dumps(jsonp)
Ejemplo n.º 18
0
 def __init__(self, db_file):
     self._db = MBTilesReader(db_file)
Ejemplo n.º 19
0
def get_metadata(map_id, name):
    mbtiles = os.path.join(settings['FLATMAP_ROOT'], map_id, 'index.mbtiles')
    return metadata(MBTilesReader(mbtiles), name)