Skip to content

Commit

Permalink
refactor render dependencies (#1029)
Browse files Browse the repository at this point in the history
* refactor render dependencies

* fix
  • Loading branch information
vincentsarago authored Dec 20, 2024
1 parent 98a417d commit 5158f9d
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 159 deletions.
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

0 comments on commit 5158f9d

Please sign in to comment.