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

check blocksize and adapt if raster is too small #82

Merged
merged 2 commits into from
Jul 17, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 30 additions & 14 deletions rio_cogeo/cogeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os
import sys
import math
import warnings
import tempfile
from contextlib import contextmanager
Expand All @@ -20,7 +21,7 @@
import mercantile
from supermercado.burntiles import tile_extrema

from rio_cogeo.errors import LossyCompression
from rio_cogeo.errors import LossyCompression, IncompatibleBlockRasterSize
from rio_cogeo.utils import (
get_maximum_overview_level,
has_alpha_band,
Expand Down Expand Up @@ -122,6 +123,30 @@ def cog_translate(
LossyCompression,
)

tilesize = min(int(dst_kwargs["blockxsize"]), int(dst_kwargs["blockysize"]))

if src_dst.width < tilesize or src_dst.height < tilesize:
tilesize = 2 ** int(math.log(min(src_dst.width, src_dst.height), 2))
if tilesize < 64:
warnings.warn(
"Raster has dimension < 64px. Output COG cannot be tiled"
" and overviews cannot be added.",
IncompatibleBlockRasterSize,
)
dst_kwargs.pop("blockxsize", None)
dst_kwargs.pop("blockysize", None)
dst_kwargs.pop("tiled")
overview_level = 0

else:
warnings.warn(
"Block Size are bigger than raster sizes. "
"Setting blocksize to {}".format(tilesize),
IncompatibleBlockRasterSize,
)
dst_kwargs["blockxsize"] = tilesize
dst_kwargs["blockysize"] = tilesize

vrt_params = dict(add_alpha=True)

if nodata is not None:
Expand All @@ -141,9 +166,6 @@ def cog_translate(
)
center = [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2]

tilesize = min(
int(dst_kwargs["blockxsize"]), int(dst_kwargs["blockysize"])
)
lat = 0 if latitude_adjustment else center[1]
max_zoom = get_max_zoom(src_dst, lat=lat, tilesize=tilesize)

Expand Down Expand Up @@ -208,17 +230,11 @@ def cog_translate(
mask_value = vrt_dst.dataset_mask(window=w)
tmp_dst.write_mask(mask_value, window=w)

if not quiet:
click.echo("Adding overviews...", err=True)

if overview_level is None:
overview_level = get_maximum_overview_level(
vrt_dst,
min(
int(dst_kwargs["blockxsize"]),
int(dst_kwargs["blockysize"]),
),
)
overview_level = get_maximum_overview_level(vrt_dst, tilesize)

if not quiet and overview_level:
click.echo("Adding overviews...", err=True)

overviews = [2 ** j for j in range(1, overview_level + 1)]
tmp_dst.build_overviews(
Expand Down
4 changes: 4 additions & 0 deletions rio_cogeo/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ class DeprecationWarning(UserWarning):

class LossyCompression(UserWarning):
"""Rio-cogeo module Lossy compression warning."""


class IncompatibleBlockRasterSize(UserWarning):
"""Rio-cogeo module incompatible raster block/size warning."""
Binary file added tests/fixtures/image_171px.tif
Binary file not shown.
Binary file added tests/fixtures/image_51px.tif
Binary file not shown.
40 changes: 38 additions & 2 deletions tests/test_cogeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from click.testing import CliRunner

import rasterio
from rio_cogeo.cogeo import cog_translate
from rio_cogeo.cogeo import cog_translate, cog_validate
from rio_cogeo.utils import has_mask_band, has_alpha_band
from rio_cogeo.errors import LossyCompression
from rio_cogeo.errors import LossyCompression, IncompatibleBlockRasterSize
from rio_cogeo.profiles import cog_profiles

from .conftest import requires_webp
Expand All @@ -32,6 +32,12 @@
raster_path_mask = os.path.join(
os.path.dirname(__file__), "fixtures", "image_rgb_mask.tif"
)
raster_path_small = os.path.join(
os.path.dirname(__file__), "fixtures", "image_171px.tif"
)
raster_path_toosmall = os.path.join(
os.path.dirname(__file__), "fixtures", "image_51px.tif"
)

jpeg_profile = cog_profiles.get("jpeg")
jpeg_profile.update({"blockxsize": 64, "blockysize": 64})
Expand All @@ -41,6 +47,7 @@
deflate_profile.update({"blockxsize": 64, "blockysize": 64})
raw_profile = cog_profiles.get("raw")
raw_profile.update({"blockxsize": 64, "blockysize": 64})
default_profile = cog_profiles.get("raw")


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -256,3 +263,32 @@ def test_cog_translate_tags():
assert src.tags()["OVR_RESAMPLING_ALG"] == "NEAREST"
assert src.tags()["DatasetName"] == "my useful dataset"
assert src.descriptions[0] == "second band"


def test_cog_translate_valid_blocksize():
"""Should work as expected (create cogeo file)."""
runner = CliRunner()
with runner.isolated_filesystem():
with pytest.warns(IncompatibleBlockRasterSize):
cog_translate(raster_path_small, "cogeo.tif", default_profile, quiet=True)
assert cog_validate("cogeo.tif")
with rasterio.open("cogeo.tif") as src:
assert src.height == 171
assert src.width == 171
assert src.is_tiled
assert src.profile["blockxsize"] == 128
assert src.profile["blockysize"] == 128
assert src.overviews(1) == [2]

with pytest.warns(IncompatibleBlockRasterSize):
cog_translate(
raster_path_toosmall, "cogeo.tif", default_profile, quiet=True
)
assert cog_validate("cogeo.tif")
with rasterio.open("cogeo.tif") as src:
assert src.height == 51
assert src.width == 51
assert not src.is_tiled
assert not src.profile.get("blockxsize")
assert not src.profile.get("blockysize")
assert not src.overviews(1)