Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor render dependencies #1029

Merged
merged 4 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,25 @@
* improve query string handling in LowerCaseQueryStringMiddleware using urlencode (author @pratapvardhan, https://github.com/developmentseed/titiler/pull/1050)
* add `titiler.core.utils.bounds_to_geometry` and reduce code duplication in factories (author @PratapVardhan, https://github.com/developmentseed/titiler/pull/1047)
* simplify image format dtype validation in `render_image` (author @PratapVardhan, https://github.com/developmentseed/titiler/pull/1046)
* remove `rescale_dependency` and `color_formula_dependency` attributes in `TilerFactory` class **breaking change**
* move `rescale` and `color_formula` QueryParameters dependencies in `ImageRenderingParams` class **breaking change**
* handle image rescaling and color_formula within `titiler.core.utils.render_image` function **breaking change**
* add `render_func: Callable[..., Tuple[bytes, str]] = render_image` attribute in `TilerFactory` class

### titiler.application

* update `/healthz` endpoint to return dependencies versions (titiler, rasterio, gdal, ...) (author @scottyhq, https://github.com/developmentseed/titiler/pull/1056)
* migrate `templates/index.html` to bootstrap5, remove unused css, reuse bs classes (author @PratapVardhan, https://github.com/developmentseed/titiler/pull/1048)

### titiler.mosaic

* remove `rescale_dependency` and `color_formula_dependency` attributes in `MosaicTilerFactory` class **breaking change**
* add `render_func: Callable[..., Tuple[bytes, str]] = render_image` attribute in `MosaicTilerFactory` class **breaking change**

### titiler.extensions

* use `factory.render_func` as render function in `wmsExtension` endpoints

### Misc

* Updated WMTS Capabilities template to avoid inserting extra new lines (author @AndrewAnnex, https://github.com/developmentseed/titiler/pull/1052).
Expand Down
102 changes: 42 additions & 60 deletions docs/src/advanced/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,32 +412,6 @@ class BidxExprParams(ExpressionParams, BidxParams):

</details>

#### `ColorFormulaParams`

Color Formula option (see https://github.com/vincentsarago/color-operations).

| Name | Type | Required | Default
| ------ | ----------|----------|--------------
| **color_formula** | Query (str) | No | None

<details>

```python
def ColorFormulaParams(
color_formula: Annotated[
Optional[str],
Query(
title="Color Formula",
description="rio-color formula (info: https://github.com/mapbox/rio-color)",
),
] = None,
) -> Optional[str]:
"""ColorFormula Parameter."""
return color_formula
```

</details>

#### `ColorMapParams`

Colormap options. See [titiler.core.dependencies](https://github.com/developmentseed/titiler/blob/e46c35c8927b207f08443a274544901eb9ef3914/src/titiler/core/titiler/core/dependencies.py#L18-L54).
Expand Down Expand Up @@ -709,9 +683,11 @@ link: https://numpy.org/doc/stable/reference/generated/numpy.histogram.html

Control output image rendering options.

| Name | Type | Required | Default
| ------ | ----------|----------|--------------
| **return_mask** | Query (bool) | No | False
| Name | Type | Required | Default
| ------ | ---------- |----------|--------------
| **rescale** | Query (str, comma delimited Numer) | No | None
| **color_formula** | Query (str) | No | None
| **return_mask** | Query (bool) | No | False

<details>

Expand All @@ -720,13 +696,49 @@ Control output image rendering options.
class ImageRenderingParams(DefaultDependency):
"""Image Rendering options."""

rescale: Annotated[
Optional[List[str]],
Query(
title="Min/Max data Rescaling",
description="comma (',') delimited Min,Max range. Can set multiple time for multiple bands.",
examples=["0,2000", "0,1000", "0,10000"], # band 1 # band 2 # band 3
),
] = None

color_formula: Annotated[
Optional[str],
Query(
title="Color Formula",
description="rio-color formula (info: https://github.com/mapbox/rio-color)",
),
] = None

add_mask: Annotated[
Optional[bool],
Query(
alias="return_mask",
description="Add mask to the output data. Defaults to `True` in rio-tiler",
description="Add mask to the output data. Defaults to `True`",
),
] = None

def __post_init__(self):
"""Post Init."""
if self.rescale:
rescale_array = []
for r in self.rescale:
parsed = tuple(
map(
float,
r.replace(" ", "").replace("[", "").replace("]", "").split(","),
)
)
assert (
len(parsed) == 2
), f"Invalid rescale values: {self.rescale}, should be of form ['min,max', 'min,max'] or [[min,max], [min, max]]"
rescale_array.append(parsed)

self.rescale: RescaleType = rescale_array # Noqa

```

</details>
Expand Down Expand Up @@ -815,36 +827,6 @@ class PreviewParams(DefaultDependency):

</details>

#### `RescalingParams`

Set Min/Max values to rescale from, to 0 -> 255.

| Name | Type | Required | Default
| ------ | ----------|----------|--------------
| **rescale** | Query (str, comma delimited Numer) | No | None

<details>

```python
def RescalingParams(
rescale: Annotated[
Optional[List[str]],
Query(
title="Min/Max data Rescaling",
description="comma (',') delimited Min,Max range. Can set multiple time for multiple bands.",
examples=["0,2000", "0,1000", "0,10000"], # band 1 # band 2 # band 3
),
] = None,
) -> Optional[RescaleType]:
"""Min/Max data Rescaling"""
if rescale:
return [tuple(map(float, r.replace(" ", "").split(","))) for r in rescale]

return None
```

</details>

#### StatisticsParams

Define options for *rio-tiler*'s statistics method.
Expand Down
7 changes: 1 addition & 6 deletions docs/src/advanced/endpoints_factories.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,12 @@ Factory meant to create endpoints for single dataset using [*rio-tiler*'s `Reade
- **img_preview_dependency**: Dependency to define image size for `/preview` and `/statistics` endpoints. Defaults to `titiler.core.dependencies.PreviewParams`.
- **img_part_dependency**: Dependency to define image size for `/bbox` and `/feature` endpoints. Defaults to `titiler.core.dependencies.PartFeatureParams`.
- **process_dependency**: Dependency to control which `algorithm` to apply to the data. Defaults to `titiler.core.algorithm.algorithms.dependency`.
- **rescale_dependency**: Dependency to set Min/Max values to rescale from, to 0 -> 255. Defaults to `titiler.core.dependencies.RescalingParams`.
- **color_formula_dependency**: Dependency to define the Color Formula. Defaults to `titiler.core.dependencies.ColorFormulaParams`.
- **colormap_dependency**: Dependency to define the Colormap options. Defaults to `titiler.core.dependencies.ColorMapParams`
- **render_dependency**: Dependency to control output image rendering options. Defaults to `titiler.core.dependencies.ImageRenderingParams`
- **environment_dependency**: Dependency to define GDAL environment at runtime. Default to `lambda: {}`.
- **supported_tms**: List of available TileMatrixSets. Defaults to `morecantile.tms`.
- **templates**: *Jinja2* templates to use in endpoints. Defaults to `titiler.core.factory.DEFAULT_TEMPLATES`.
- **render_func**: Image rendering method. Defaults to `titiler.core.utils.render_image`.
- **add_preview**: . Add `/preview` endpoint to the router. Defaults to `True`.
- **add_part**: . Add `/bbox` and `/feature` endpoints to the router. Defaults to `True`.
- **add_viewer**: . Add `/map` endpoints to the router. Defaults to `True`.
Expand Down Expand Up @@ -304,8 +303,6 @@ Endpoints factory for mosaics, built on top of [MosaicJSON](https://github.com/d
- **dataset_dependency**: Dependency to overwrite `nodata` value, apply `rescaling` and change the `I/O` or `Warp` resamplings. Defaults to `titiler.core.dependencies.DatasetParams`.
- **tile_dependency**: Dependency to define `buffer` and `padding` to apply at tile creation. Defaults to `titiler.core.dependencies.TileParams`.
- **process_dependency**: Dependency to control which `algorithm` to apply to the data. Defaults to `titiler.core.algorithm.algorithms.dependency`.
- **rescale_dependency**: Dependency to set Min/Max values to rescale from, to 0 -> 255. Defaults to `titiler.core.dependencies.RescalingParams`.
- **color_formula_dependency**: Dependency to define the Color Formula. Defaults to `titiler.core.dependencies.ColorFormulaParams`.
- **colormap_dependency**: Dependency to define the Colormap options. Defaults to `titiler.core.dependencies.ColorMapParams`
- **render_dependency**: Dependency to control output image rendering options. Defaults to `titiler.core.dependencies.ImageRenderingParams`
- **pixel_selection_dependency**: Dependency to select the `pixel_selection` method. Defaults to `titiler.mosaic.factory.PixelSelectionParams`.
Expand Down Expand Up @@ -353,8 +350,6 @@ class: `titiler.xarray.factory.TilerFactory`
- **histogram_dependency**: Dependency to define *numpy*'s histogram options used in `/statistics` endpoints. Defaults to `titiler.core.dependencies.HistogramParams`.
- **img_part_dependency**: Dependency to define image size for `/bbox` and `/feature` endpoints. Defaults to `titiler.xarray.dependencies.PartFeatureParams`.
- **process_dependency**: Dependency to control which `algorithm` to apply to the data. Defaults to `titiler.core.algorithm.algorithms.dependency`.
- **rescale_dependency**: Dependency to set Min/Max values to rescale from, to 0 -> 255. Defaults to `titiler.core.dependencies.RescalingParams`.
- **color_formula_dependency**: Dependency to define the Color Formula. Defaults to `titiler.core.dependencies.ColorFormulaParams`.
- **colormap_dependency**: Dependency to define the Colormap options. Defaults to `titiler.core.dependencies.ColorMapParams`
- **render_dependency**: Dependency to control output image rendering options. Defaults to `titiler.core.dependencies.ImageRenderingParams`
- **environment_dependency**: Dependency to define GDAL environment at runtime. Default to `lambda: {}`.
Expand Down
1 change: 1 addition & 0 deletions src/titiler/core/tests/test_CustomRender.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class CustomRenderParams(ImageRenderingParams):

def __post_init__(self):
"""post init."""
super().__post_init__()
if self.nodata is not None:
self.nodata = numpy.nan if self.nodata == "nan" else float(self.nodata)

Expand Down
4 changes: 2 additions & 2 deletions src/titiler/core/tests/test_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,9 +500,9 @@ def test_rescale_params():
app = FastAPI()

@app.get("/")
def main(rescale=Depends(dependencies.RescalingParams)):
def main(params=Depends(dependencies.ImageRenderingParams)):
"""return rescale."""
return rescale
return params.rescale

client = TestClient(app)

Expand Down
50 changes: 41 additions & 9 deletions src/titiler/core/tests/test_factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pathlib
import warnings
import xml.etree.ElementTree as ET
from dataclasses import dataclass
from enum import Enum
from io import BytesIO
from typing import Dict, Optional, Sequence, Type
Expand All @@ -26,8 +27,9 @@
from rio_tiler.io import BaseReader, MultiBandReader, Reader, STACReader
from starlette.requests import Request
from starlette.testclient import TestClient
from typing_extensions import Annotated

from titiler.core.dependencies import RescaleType
from titiler.core import dependencies
from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers
from titiler.core.factory import (
AlgorithmFactory,
Expand Down Expand Up @@ -1757,11 +1759,34 @@ def test_AutoFormat_Colormap():
def test_rescale_dependency():
"""Ensure that we can set default rescale values via the rescale_dependency"""

def custom_rescale_params() -> Optional[RescaleType]:
return [(0, 100)]
@dataclass
class ImageRenderingParams(dependencies.ImageRenderingParams):
"""Custom ImageParams."""

def __post_init__(self):
if self.rescale:
rescale_array = []
for r in self.rescale:
parsed = tuple(
map(
float,
r.replace(" ", "")
.replace("[", "")
.replace("]", "")
.split(","),
)
)
assert (
len(parsed) == 2
), f"Invalid rescale values: {self.rescale}, should be of form ['min,max', 'min,max'] or [[min,max], [min, max]]"
rescale_array.append(parsed)

self.rescale = rescale_array # Noqa
else:
self.rescale = [(0, 100)]

cog = TilerFactory()
cog_custom_range = TilerFactory(rescale_dependency=custom_rescale_params)
cog_custom_range = TilerFactory(render_dependency=ImageRenderingParams)

app = FastAPI()
app.include_router(cog.router, prefix="/cog")
Expand Down Expand Up @@ -1839,13 +1864,20 @@ def test_dst_crs_option():
def test_color_formula_dependency():
"""Ensure that we can set default color formulae via the color_formula_dependency"""

def custom_color_formula_params() -> Optional[str]:
return "sigmoidal R 7 0.4"
@dataclass
class ImageRenderingParams(dependencies.ImageRenderingParams):
"""Custom ImageParams."""

color_formula: Annotated[
Optional[str],
Query(
title="Color Formula",
description="rio-color formula (info: https://github.com/mapbox/rio-color)",
),
] = "sigmoidal R 7 0.4"

cog = TilerFactory()
cog_custom_color_formula = TilerFactory(
color_formula_dependency=custom_color_formula_params
)
cog_custom_color_formula = TilerFactory(render_dependency=ImageRenderingParams)

app = FastAPI()
app.include_router(cog.router, prefix="/cog")
Expand Down
47 changes: 46 additions & 1 deletion src/titiler/core/titiler/core/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,30 @@ def __post_init__(self):
self.unscale = bool(self.unscale)


RescaleType = List[Tuple[float, float]]


@dataclass
class ImageRenderingParams(DefaultDependency):
"""Image Rendering options."""

rescale: Annotated[
Optional[List[str]],
Query(
title="Min/Max data Rescaling",
description="comma (',') delimited Min,Max range. Can set multiple time for multiple bands.",
examples=["0,2000", "0,1000", "0,10000"], # band 1 # band 2 # band 3
),
] = None

color_formula: Annotated[
Optional[str],
Query(
title="Color Formula",
description="rio-color formula (info: https://github.com/mapbox/rio-color)",
),
] = None

add_mask: Annotated[
Optional[bool],
Query(
Expand All @@ -437,8 +457,23 @@ class ImageRenderingParams(DefaultDependency):
),
] = None

def __post_init__(self):
"""Post Init."""
if self.rescale:
rescale_array = []
for r in self.rescale:
parsed = tuple(
map(
float,
r.replace(" ", "").replace("[", "").replace("]", "").split(","),
)
)
assert (
len(parsed) == 2
), f"Invalid rescale values: {self.rescale}, should be of form ['min,max', 'min,max'] or [[min,max], [min, max]]"
rescale_array.append(parsed)

RescaleType = List[Tuple[float, float]]
self.rescale: RescaleType = rescale_array


def RescalingParams(
Expand All @@ -452,6 +487,11 @@ def RescalingParams(
] = None,
) -> Optional[RescaleType]:
"""Min/Max data Rescaling"""
warnings.warn(
"RescalingParams is deprecated and set to be removed in 0.20",
DeprecationWarning,
stacklevel=1,
)
if rescale:
rescale_array = []
for r in rescale:
Expand Down Expand Up @@ -646,6 +686,11 @@ def ColorFormulaParams(
] = None,
) -> Optional[str]:
"""ColorFormula Parameter."""
warnings.warn(
"ColorFormulaParams is deprecated and set to be removed in 0.20",
DeprecationWarning,
stacklevel=1,
)
return color_formula


Expand Down
Loading
Loading