Exemple #1
0
def raster2pyramid(
    input_file,
    output_dir,
    options
    ):
    """
    Creates a tile pyramid out of an input raster dataset.
    """
    pyramid_type = options["pyramid_type"]
    scale_method = options["scale_method"]
    output_format = options["output_format"]
    resampling = options["resampling"]
    zoom = options["zoom"]
    bounds = options["bounds"]
    overwrite = options["overwrite"]

    # Prepare process parameters
    minzoom, maxzoom = _get_zoom(zoom, input_file, pyramid_type)
    process_file = os.path.join(
        os.path.dirname(os.path.realpath(__file__)),
        "tilify.py"
    )

    with rasterio.open(input_file, "r") as input_raster:
        output_bands = input_raster.count
        input_dtype = input_raster.dtypes[0]
        output_dtype = input_raster.dtypes[0]
        nodataval = input_raster.nodatavals[0]
        if not nodataval:
            nodataval = 0
        if output_format == "PNG":
            if output_bands > 3:
                output_bands = 3
                output_dtype = 'uint8'
        scales_minmax = ()
        if scale_method == "dtype_scale":
            for index in range(1, output_bands+1):
                scales_minmax += (DTYPE_RANGES[input_dtype], )
        elif scale_method == "minmax_scale":
            for index in range(1, output_bands+1):
                band = input_raster.read(index)
                scales_minmax += ((band.min(), band.max()), )
        elif scale_method == "crop":
            for index in range(1, output_bands+1):
                scales_minmax += ((0, 255), )
        if input_dtype == "uint8":
            scale_method = None
            scales_minmax = ()
            for index in range(1, output_bands+1):
                scales_minmax += ((None, None), )

    # Create configuration
    config = {}
    config.update(
        process_file=process_file,
        output={
            "path": output_dir,
            "format": output_format,
            "type": pyramid_type,
            "bands": output_bands,
            "dtype": output_dtype
            },
        scale_method=scale_method,
        scales_minmax=scales_minmax,
        input_files={"raster": input_file},
        config_dir=os.getcwd(),
        process_minzoom=minzoom,
        process_maxzoom=maxzoom,
        nodataval=nodataval,
        resampling=resampling,
        bounds=bounds,
        pixelbuffer=5,
        baselevel={"zoom": maxzoom, "resampling": resampling}
    )

    LOGGER.info("preparing process ...")

    try:
        mapchete = Mapchete(
            MapcheteConfig(
                config,
                zoom=zoom,
                bounds=bounds
            )
        )
    except PyCompileError as error:
        print error
        return
    except:
        raise

    # Prepare output directory and logging
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    logging.config.dictConfig(get_log_config(mapchete))

    for zoom in reversed(range(minzoom, maxzoom+1)):
        # Determine work tiles and run
        work_tiles = mapchete.get_work_tiles(zoom)
        func = partial(_worker,
            mapchete=mapchete,
            overwrite=overwrite
        )
        pool = Pool()
        try:
            pool.map_async(func, work_tiles)
            pool.close()
        except KeyboardInterrupt:
            LOGGER.info(
                "Caught KeyboardInterrupt, terminating workers"
                )
            pool.terminate()
            break
        except:
            raise
        finally:
            pool.close()
            pool.join()
Exemple #2
0
def main(args=None):
    """
    Creates the Mapchete host and serves both web page with OpenLayers and the
    WMTS simple REST endpoint.
    """

    if args is None:
        args = sys.argv[1:]
        parser = argparse.ArgumentParser()
        parser.add_argument("mapchete_file", type=str)
        parser.add_argument("--port", "-p", type=int, default=5000)
        parser.add_argument("--zoom", "-z", type=int, nargs='*', )
        parser.add_argument("--bounds", "-b", type=float, nargs='*')
        parser.add_argument("--log", action="store_true")
        parser.add_argument("--overwrite", action="store_true")
        parser.add_argument("--input_file", type=str)
        parsed = parser.parse_args(args)
    elif isinstance(args, argparse.Namespace):
        parsed = args
    else:
        raise RuntimeError("invalid arguments for mapchete serve")

    try:
        assert os.path.splitext(parsed.mapchete_file)[1] == ".mapchete"
    except:
        raise IOError("must be a valid mapchete file")

    try:
        LOGGER.info("preparing process ...")
        mapchete = Mapchete(
            MapcheteConfig(
                parsed.mapchete_file,
                zoom=parsed.zoom,
                bounds=parsed.bounds,
                single_input_file=parsed.input_file
            )
        )
    except:
        raise

    app = Flask(__name__)

    logging.config.dictConfig(get_log_config(mapchete))
    metatile_cache = {}
    metatile_lock = threading.Lock()

    @app.route('/', methods=['GET'])
    def return_index():
        """
        Renders and hosts the appropriate OpenLayers instance.
        """
        index_html = pkgutil.get_data('mapchete.static', 'index.html')
        process_bounds = mapchete.config.process_bounds()
        if not process_bounds:
            process_bounds = (
                mapchete.tile_pyramid.left,
                mapchete.tile_pyramid.bottom,
                mapchete.tile_pyramid.right,
                mapchete.tile_pyramid.top
            )
        return render_template_string(
            index_html,
            srid=mapchete.tile_pyramid.srid,
            process_bounds=",".join(map(str, process_bounds)),
            is_mercator=(mapchete.tile_pyramid.srid == 3857)
        )


    tile_base_url = '/wmts_simple/1.0.0/mapchete/default/'
    if mapchete.tile_pyramid.srid == 3857:
        tile_base_url += "g/"
    else:
        tile_base_url += "WGS84/"
    @app.route(
        tile_base_url+'<int:zoom>/<int:row>/<int:col>.png',
        methods=['GET']
        )
    def get(zoom, row, col):
        """
        Returns processed, empty or error (in pink color) tile.
        """
        tile = mapchete.tile_pyramid.tilepyramid.tile(zoom, row, col)
        try:
            metatile = mapchete.tile(
                mapchete.tile_pyramid.tile(
                    tile.zoom,
                    int(tile.row/mapchete.config.metatiling),
                    int(tile.col/mapchete.config.metatiling),
                    )
                )
            with metatile_lock:
                metatile_event = metatile_cache.get(metatile.id)
                if not metatile_event:
                    metatile_cache[metatile.id] = threading.Event()

            if metatile_event:
                LOGGER.info("%s waiting for metatile %s",
                    tile.id,
                    metatile.id
                    )
                metatile_event.wait()
                try:
                    image = mapchete.get(tile)
                except:
                    raise
            else:
                LOGGER.info("%s getting metatile %s",
                    tile.id,
                    metatile.id
                    )
                try:
                    image = mapchete.get(tile, overwrite=parsed.overwrite)
                except:
                    raise
                finally:
                    with metatile_lock:
                        metatile_event = metatile_cache.get(metatile.id)
                        del metatile_cache[metatile.id]
                        metatile_event.set()

            if image:
                resp = make_response(image)
                # set no-cache header:
                resp.cache_control.no_cache = True
                LOGGER.info((tile.id, "ok", "image sent"))
                return resp
            else:
                raise IOError("no image returned")

        except Exception as exception:
            error_msg = (tile.id, "failed", exception)
            LOGGER.error(error_msg)
            size = mapchete.tile_pyramid.tilepyramid.tile_size
            empty_image = Image.new('RGBA', (size, size))
            pixels = empty_image.load()
            for y_idx in xrange(size):
                for x_idx in xrange(size):
                    pixels[x_idx, y_idx] = (255, 0, 0, 128)
            out_img = io.BytesIO()
            empty_image.save(out_img, 'PNG')
            out_img.seek(0)
            resp = make_response(send_file(out_img, mimetype='image/png'))
            resp.cache_control.no_cache = True
            return resp

    app.run(
        threaded=True,
        debug=True,
        port=parsed.port,
        extra_files=[parsed.mapchete_file]
        )