summit/backend/venv/lib/python3.12/site-packages/rasterio/rio/create.py

167 lines
5.2 KiB
Python

"""The rio create command."""
import click
import json
import os
import rasterio
from rasterio.crs import CRS
from rasterio.errors import (
CRSError,
FileOverwriteError,
RasterioIOError,
)
from rasterio.rio import options
from rasterio.transform import Affine, guard_transform
def crs_handler(ctx, param, value):
"""Get crs value from the command line."""
retval = None
if value is not None:
try:
retval = CRS.from_string(value)
except CRSError:
raise click.BadParameter(
f"{value} is not a recognized CRS.", param=param, param_hint="crs"
)
return retval
def transform_handler(ctx, param, value):
"""Get transform value from the command line."""
retval = None
if value is not None:
try:
value = json.loads(value)
retval = guard_transform(value)
except Exception:
raise click.BadParameter(
f"{value} is not recognized as a transformarray.",
param=param,
param_hint="transform",
)
return retval
@click.command(short_help="Create an empty or filled dataset.")
@options.file_out_arg
@options.format_opt
@options.dtype_opt
@click.option("--count", "-n", type=int, help="Number of raster bands.")
@click.option("--height", "-h", type=int, help="Raster height, or number of rows.")
@click.option("--width", "-w", type=int, help="Raster width, or number of columns.")
@options.nodata_opt
@click.option(
"--crs", callback=crs_handler, default=None, help="Coordinate reference system."
)
@click.option(
"--transform",
callback=transform_handler,
help="Affine transform matrix. Overrides any given bounds option.",
)
@options.bounds_opt
@options.overwrite_opt
@options.creation_options
@click.pass_context
def create(
ctx,
output,
driver,
dtype,
count,
height,
width,
nodata,
crs,
transform,
bounds,
overwrite,
creation_options,
):
"""Create an empty dataset.
The fundamental, required parameters are: format driver name, data
type, count of bands, height and width in pixels. Long and short
options are provided for each of these. Coordinate reference system
and affine transformation matrix are not strictly required and have
long options only. All other format specific creation outputs must
be specified using the --co option.
Simple north-up, non-rotated georeferencing can be set by using the
--bounds option. The --transform option will assign an arbitrarily
rotated affine transformation matrix to the dataset. Ground control
points, rational polynomial coefficients, and geolocation matrices
are not supported.
The pixel values of an empty dataset are format specific. "Smart"
formats like GTiff use 0 or the nodata value if provided.
Example:
\b
$ rio create new.tif -f GTiff -t uint8 -n 3 -h 512 -w 512 \\
> --co tiled=true --co blockxsize=256 --co blockysize=256
The command above produces a 3-band GeoTIFF with 256 x 256 internal
tiling.
"""
# Preventing rio create from overwriting local and remote files,
# objects, and datasets is complicated.
if os.path.exists(output):
if not overwrite:
raise FileOverwriteError(
"File exists and won't be overwritten without use of the '--overwrite' option."
)
else: # Check remote or other non-file output.
try:
with rasterio.open(output) as dataset:
# Dataset exists. May or may not be overwritten.
if not overwrite:
raise FileOverwriteError(
"Dataset exists and won't be overwritten without use of the '--overwrite' option."
)
except RasterioIOError as exc:
# TODO: raise a different exception from rasterio.open() in
# this case?
if "No such file or directory" in str(exc):
pass # Good, output does not exist. Continue with no error.
else:
# Remote output exists, but is not a rasterio dataset.
if not overwrite:
raise FileOverwriteError(
"Object exists and won't be overwritten without use of the '--overwrite' option."
)
# Prepare the dataset's georeferencing.
geo_transform = None
if bounds:
left, bottom, right, top = bounds
sx = (right - left) / width
sy = (bottom - top) / height
geo_transform = Affine.translation(left, top) * Affine.scale(sx, sy)
if transform:
if geo_transform is not None:
click.echo(
"--transform value is overriding --bounds value. "
"Use only one of these options to avoid this warning.",
err=True,
)
geo_transform = transform
profile = dict(
driver=driver,
dtype=dtype,
count=count,
height=height,
width=width,
nodata=nodata,
crs=crs,
transform=geo_transform,
**creation_options,
)
with ctx.obj["env"], rasterio.open(output, "w", **profile) as dataset:
pass