def test_profiles_jpeg(): """Should work as expected (return jpeg profile).""" profile = cog_profiles.get("jpeg") assert profile["tiled"] assert profile["compress"] == "JPEG" assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["photometric"] == "YCbCr" assert profile["interleave"] == "pixel" profile = cog_profiles.get("JPEG") assert profile["compress"] == "JPEG"
def overview(input_mosaic, cogeo_profile, prefix, threads, overview_level, creation_options): """Create COG overviews for a mosaic.""" mosaic_def = get_mosaic_content(input_mosaic) output_profile = cog_profiles.get(cogeo_profile) output_profile.update(dict(BIGTIFF=os.environ.get("BIGTIFF", "IF_SAFER"))) if creation_options: output_profile.update(creation_options) config = dict( GDAL_NUM_THREADS="ALL_CPU", GDAL_TIFF_INTERNAL_MASK=os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), GDAL_TIFF_OVR_BLOCKSIZE="128", ) if not prefix: prefix = os.path.basename(input_mosaic).split(".")[0] create_low_level_cogs( mosaic_def, output_profile, prefix, max_overview_level=overview_level, config=config, threads=threads, )
def test_web_align_cogeo_gdal(): """Test Web-Optimized COG conformance with GDAL.""" runner = CliRunner() with runner.isolated_filesystem(): web_profile = cog_profiles.get("raw") web_profile.update({"blockxsize": 256, "blockysize": 256}) config = dict(GDAL_TIFF_OVR_BLOCKSIZE="256") cog_translate( raster_path_web, "cogeo.tif", web_profile, quiet=True, web_optimized=True, config=config, ) cog_translate( raster_path_web, "cogeo_gdal.tif", web_profile, quiet=True, web_optimized=True, config=config, use_cog_driver=True, ) with rasterio.open("cogeo.tif") as cog_dst, rasterio.open( "cogeo_gdal.tif") as cog_gdal: assert cog_dst.shape == cog_gdal.shape for i in range(0, 4): assert round(cog_dst.bounds[i], 5) == round(cog_gdal.bounds[i], 5) # Aligned Overviews cog_translate( raster_path_web, "cogeo.tif", web_profile, quiet=True, web_optimized=True, config=config, aligned_levels=4, ) cog_translate( raster_path_web, "cogeo_gdal.tif", web_profile, quiet=True, web_optimized=True, config=config, aligned_levels=4, use_cog_driver=True, ) with rasterio.open("cogeo.tif") as cog_dst, rasterio.open( "cogeo_gdal.tif") as cog_gdal: assert cog_dst.shape == cog_gdal.shape for i in range(0, 4): assert round(cog_dst.bounds[i], 5) == round(cog_gdal.bounds[i], 5)
def cogify(fin, fout, nodata=None): """ Turn a geospatial image into a COG """ logger.debug(f"Turning {fin} into COG named {fout}") output_profile = cog_profiles.get('deflate') output_profile.update(dict(BIGTIFF=os.environ.get("BIGTIFF", "IF_SAFER"))) output_profile['blockxsize'] = 256 output_profile['blockysize'] = 256 threads = 1 overview_blocksize = 128 config = dict( NUM_THREADS=threads, GDAL_TIFF_INTERNAL_MASK=os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), GDAL_TIFF_OVR_BLOCKSIZE=str(overview_blocksize), ) cog_translate(fin, fout, output_profile, config=config, nodata=nodata, overview_resampling="bilinear", add_mask=False, web_optimized=False) return fout
def test_gdal_cog_compareWeb(runner): """Test GDAL COG.""" with runner.isolated_filesystem(): profile = cog_profiles.get("jpeg") profile["blockxsize"] = 256 profile["blockysize"] = 256 # rio cogeo GDAL COG cog_translate( raster_path_rgba, "gdalcogeo.tif", profile.copy(), quiet=True, use_cog_driver=True, web_optimized=True, ) # pure COG copy( raster_path_rgba, "cog.tif", driver="COG", blocksize=256, compress="JPEG", TILING_SCHEME="GoogleMapsCompatible", ) with rasterio.open("gdalcogeo.tif") as gdalcogeo, rasterio.open( "cog.tif" ) as cog: assert cog.meta == gdalcogeo.meta
def generate_tiff_from_array(meta, array, obs_path): temp_tiff_file = tempfile.mktemp(suffix=".tiff") temp_cog_file = tempfile.mktemp(suffix=".tiff") with rasterio.open(temp_tiff_file, mode='w', driver=meta.get('driver'), width=meta.get('width'), height=meta.get('height'), transform=meta.get('transform'), crs=meta.get('crs'), count=meta.get('count'), nodata=meta.get('nodata'), dtype=array.dtype) as dst: for band in range(0, meta.get('count')): dst.write_band(band + 1, array[band]) try: # convert tiff to cog output_profile = cog_profiles.get("deflate") output_profile.update({"BLOCKXSIZE": 256, "BLOCKYSIZE": 256}) config = dict( NUM_THREADS=8, GDAL_TIFF_INTERNAL_MASK=os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), GDAL_TIFF_OVR_BLOCKSIZE=str(os.environ.get("GDAL_TIFF_OVR_BLOCKSIZE", 128)) ) cog_translate(temp_tiff_file, temp_cog_file, output_profile, add_mask=True, web_optimized=False, config=config) s3 = S3() return s3.upload(local_file=temp_cog_file, obs_path=obs_path) except Exception as e: raise ConvertCogError(e.__str__()) finally: if os.path.exists(temp_tiff_file): os.remove(temp_tiff_file) if os.path.exists(temp_cog_file): os.remove(temp_cog_file)
def create_cog(input, output, overview_resampling, bidx): cogeo_profile = 'deflate' nodata = -1 overview_level = 6 overview_resampling = overview_resampling threads = 8 output_profile = cog_profiles.get(cogeo_profile) output_profile.update(dict(BIGTIFF=os.environ.get("BIGTIFF", "IF_SAFER"))) block_size = min(int(output_profile["blockxsize"]), int(output_profile["blockysize"])) config = dict( NUM_THREADS=threads, GDAL_TIFF_INTERNAL_MASK=os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), GDAL_TIFF_OVR_BLOCKSIZE=os.environ.get("GDAL_TIFF_OVR_BLOCKSIZE", block_size), ) cog_translate(src_path=input, dst_path=output, dst_kwargs=output_profile, indexes=bidx, nodata=nodata, web_optimized=False, add_mask=False, overview_level=overview_level, overview_resampling=overview_resampling, config=config, quiet=False)
def to_obstiff(arr, obs_path, proj="EPSG:4326", spec=None, bands=None, **kwargs): temp_file = tempfile.mktemp(suffix=".tiff") temp_cog_file = tempfile.mktemp(suffix=".tiff") # save to tiff to_geotiff(arr, path=temp_file, proj=proj, spec=spec, bands=bands, **kwargs) try: # convert tiff to cog output_profile = cog_profiles.get("deflate") output_profile.update({"BLOCKXSIZE": 256, "BLOCKYSIZE": 256}) config = dict( NUM_THREADS=8, GDAL_TIFF_INTERNAL_MASK=os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), GDAL_TIFF_OVR_BLOCKSIZE=str(os.environ.get("GDAL_TIFF_OVR_BLOCKSIZE", 128)) ) cog_translate(temp_file, temp_cog_file, output_profile, add_mask=True, web_optimized=False, config=config) s3 = S3() return s3.upload(local_file=temp_cog_file, obs_path=obs_path) except Exception as e: raise ConvertCogError(e.__str__()) finally: if os.path.exists(temp_file): os.remove(temp_file) if os.path.exists(temp_cog_file): os.remove(temp_cog_file)
def cogeo( input, output, bidx, cogeo_profile, nodata, alpha, overview_level, threads, creation_options, ): """Create Cloud Optimized Geotiff.""" if nodata is not None and alpha is not None: raise click.ClickException('Incompatible options "alpha" and "nodata"') output_profile = cog_profiles.get(cogeo_profile) output_profile.update(dict(BIGTIFF=os.environ.get("BIGTIFF", "IF_SAFER"))) if creation_options: output_profile.update(creation_options) block_size = min(output_profile["blockxsize"], output_profile["blockysize"]) config = dict( NUM_THREADS=threads, GDAL_TIFF_INTERNAL_MASK=os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), GDAL_TIFF_OVR_BLOCKSIZE=os.environ.get("GDAL_TIFF_OVR_BLOCKSIZE", block_size), ) cog_translate( input, output, output_profile, bidx, nodata, alpha, overview_level, config )
def create_cog_in_s3(services, profile, path, raster, bucket_name, nodata=None, tags=None): with MemoryFile() as dst_file: with MemoryFile() as memfile: with memfile.open(**profile) as mem: if nodata: mem.nodata = nodata mem.write_band(1, raster) if tags: mem.update_tags(**tags) dst_profile = cog_profiles.get("deflate") cog_translate(mem, dst_file.name, dst_profile, in_memory=True, quiet=True) services.upload_fileobj_S3(dst_file, path, {'ACL': 'public-read'}, bucket_name=bucket_name) return True
def cogify(fin, fout, nodata=None, web_optimized=False, blocksize=256, overview_blocksize=128, overview_resampling='nearest'): """ Turn a geospatial image into a COG """ output_profile = cog_profiles.get('deflate') output_profile.update({ "BIGTIFF": getenv("BIGTIFF", "IF_SAFER"), "blockxsize": blocksize, "blockysize": blocksize, "PREDICTOR": 2 }) config = { "NUM_THREADS": "ALL_CPUS", "GDAL_TIFF_INTERNAL_MASK": getenv("GDAL_TIFF_INTERNAL_MASK", True), "GDAL_TIFF_OVR_BLOCKSIZE": str(overview_blocksize) } cog_translate(fin, fout, output_profile, config=config, nodata=nodata, overview_resampling=overview_resampling, add_mask=False, web_optimized=web_optimized) return fout
def mem_cog(raster, meta, filename): config = dict( GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_INTERNAL_MASK=False, GDAL_TIFF_OVR_BLOCKSIZE="128", ) with MemoryFile() as memfile: with memfile.open(**meta) as mem: # Populate the input file with numpy array mem.write(raster) dst_profile = cog_profiles.get("deflate") dst_profile.update(dict(BIGTIFF="IF_SAFER")) cog_translate(mem, filename, dst_profile, nodata=0, add_mask=False, config=config, in_memory=True, quiet=True) if cog_validate(filename): print('COGs created and validated') with open('cog_list_' + time_frame + '.txt', 'a') as f: print(f"{filename}", file=f)
def _translate(src_path, dst_path, profile="webp", profile_options={}, **options): """Convert image to COG.""" output_profile = cog_profiles.get(profile) output_profile.update(dict(BIGTIFF="IF_SAFER")) output_profile.update(profile_options) config = dict( GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_INTERNAL_MASK=True, GDAL_TIFF_OVR_BLOCKSIZE="128", ) cog_translate( src_path, dst_path, output_profile, config=config, in_memory=False, quiet=True, allow_intermediate_compression=True, **options, ) return True
def _translate(src_path, dst_path, profile="webp", profile_options={}, **options): #source: https://github.com/cogeotiff/rio-cogeo """Convert image to COG.""" # Format creation option (see gdalwarp `-co` option) output_profile = cog_profiles.get(profile) output_profile.update(dict(BIGTIFF="IF_SAFER")) output_profile.update(profile_options) # Dataset Open option (see gdalwarp `-oo` option) config = dict( GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_INTERNAL_MASK=True, GDAL_TIFF_OVR_BLOCKSIZE="128", ) cog_translate( src_path, dst_path, output_profile, config=config, in_memory=False, quiet=True, **options, ) return True
def viz(src_paths, style, port, mapbox_token, no_check): """Rasterio Viz cli.""" # Check if cog src_paths = list(src_paths) with ExitStack() as ctx: for ii, src_path in enumerate(src_paths): if not no_check and not cog_validate(src_path): # create tmp COG click.echo("create temporaty COG") tmp_path = ctx.enter_context(TemporaryRasterFile(src_path)) output_profile = cog_profiles.get("deflate") output_profile.update(dict(blockxsize="256", blockysize="256")) config = dict( GDAL_TIFF_INTERNAL_MASK=os.environ.get( "GDAL_TIFF_INTERNAL_MASK", True ), GDAL_TIFF_OVR_BLOCKSIZE="128", ) cog_translate(src_path, tmp_path.name, output_profile, config=config) src_paths[ii] = tmp_path.name src_dst = raster.RasterTiles(src_paths) application = app.viz(src_dst, token=mapbox_token, port=port) url = application.get_template_url() click.echo(f"Viewer started at {url}", err=True) click.launch(url) application.start()
def raster_to_cog(raster, transform, dst_path, block_size=None, nodata=None): block_size = 256 if block_size is None else block_size nrows, ncols = np.shape(raster) # Source profile. src_profile = dict( driver='GTiff', height=nrows, width=ncols, count=1, dtype=raster.dtype, # if data_type is None else data_type, crs='EPSG:3857', transform=transform, nodata=np.nan if nodata is None else nodata, ) # Write data. with MemoryFile() as memfile: with memfile.open(**src_profile) as mem: # Write raster to mem file. mem.write(raster, 1) # Copy to disk. dst_profile = cog_profiles.get("raw") dst_profile["blockxsize"] = block_size dst_profile["blockysize"] = block_size cog_translate(mem, dst_path, dst_profile, in_memory=True, quiet=True, web_optimized=True)
def test_cog_translate_web_align(): """ Test Web-Optimized COG. - Test COG bounds (thus block) is aligned with Zoom levels """ tms = morecantile.tms.get("WebMercatorQuad") runner = CliRunner() with runner.isolated_filesystem(): web_profile = cog_profiles.get("raw") web_profile.update({"blockxsize": 256, "blockysize": 256}) config = dict(GDAL_TIFF_OVR_BLOCKSIZE="256") with rasterio.open(raster_path_web) as src_dst: _, max_zoom = get_zooms(src_dst) cog_translate( raster_path_web, "cogeo.tif", web_profile, quiet=True, web_optimized=True, config=config, aligned_levels=2, ) with COGReader(raster_path_web) as src_dst: bounds = src_dst.bounds with COGReader("cogeo.tif") as cog: _, max_zoom = get_zooms(cog.dataset) ulTile = tms.xy_bounds(tms.tile(bounds[0], bounds[3], max_zoom - 2)) assert round(cog.dataset.bounds[0], 5) == round(ulTile.left, 5) assert round(cog.dataset.bounds[3], 5) == round(ulTile.top, 5) lrTile = tms.xy_bounds(tms.tile(bounds[2], bounds[1], max_zoom - 2)) assert round(cog.dataset.bounds[2], 5) == round(lrTile.right, 5) assert round(cog.dataset.bounds[1], 5) == round(lrTile.bottom, 5) cog_translate( raster_path_web, "cogeo.tif", web_profile, quiet=True, web_optimized=True, config=config, aligned_levels=3, ) with COGReader(raster_path_web) as src_dst: bounds = src_dst.bounds with COGReader("cogeo.tif") as cog_dst: _, max_zoom = get_zooms(cog_dst.dataset) ulTile = tms.xy_bounds(tms.tile(bounds[0], bounds[3], max_zoom - 3)) assert round(cog_dst.dataset.bounds[0], 5) == round(ulTile.left, 5) assert round(cog_dst.dataset.bounds[3], 5) == round(ulTile.top, 5) lrTile = tms.xy_bounds(tms.tile(bounds[2], bounds[1], max_zoom - 3)) assert round(cog_dst.dataset.bounds[2], 5) == round(lrTile.right, 5) assert round(cog_dst.dataset.bounds[1], 5) == round(lrTile.bottom, 5)
def test_profiles_packbits(): """Should work as expected (return packbits profile).""" profile = cog_profiles.get("packbits") assert profile["tiled"] assert profile["compress"] == "PACKBITS" assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["interleave"] == "pixel"
def test_profiles_deflate(): """Should work as expected (return deflate profile).""" profile = cog_profiles.get("deflate") assert profile["tiled"] assert profile["compress"] == "DEFLATE" assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["interleave"] == "pixel"
def test_profiles_lzw(): """Should work as expected (return lzw profile).""" profile = cog_profiles.get("lzw") assert profile["tiled"] assert profile["compress"] == "LZW" assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["interleave"] == "pixel"
def test_profiles_webp(): """Should work as expected (return webp profile).""" profile = cog_profiles.get("webp") assert profile["tiled"] assert profile["compress"] == "WEBP" assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["interleave"] == "pixel"
def test_profiles_lerc_zstd(): """Should work as expected (return lerc_deflate profile).""" profile = cog_profiles.get("lerc_zstd") assert profile["tiled"] assert profile["compress"] == "LERC_ZSTD" assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["interleave"] == "pixel"
def test_profiles_raw(): """Should work as expected (return packbits profile).""" profile = cog_profiles.get("raw") assert profile["tiled"] assert not profile.get("compress") assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["interleave"] == "pixel"
def process( url: str, out_bucket: str, out_key: str, profile: str = "webp", profile_options: Dict = {}, allow_remote_read: bool = False, copy_valid_cog: bool = False, **options: Any, ) -> None: """Download, convert and upload.""" url_info = urlparse(url.strip()) if url_info.scheme not in ["http", "https", "s3"]: raise Exception(f"Unsuported scheme {url_info.scheme}") if allow_remote_read: src_path = url else: src_path = "/tmp/" + os.path.basename(url_info.path) if url_info.scheme.startswith("http"): wget.download(url, src_path) elif url_info.scheme == "s3": in_bucket = url_info.netloc in_key = url_info.path.strip("/") _s3_download(in_bucket, in_key, src_path) if copy_valid_cog and cog_validate(src_path): with open(src_path, "rb") as f: _upload_obj(f, out_bucket, out_key) else: config = dict( GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_INTERNAL_MASK=True, GDAL_TIFF_OVR_BLOCKSIZE="128", ) output_profile = cog_profiles.get(profile) output_profile.update(dict(BIGTIFF="IF_SAFER")) output_profile.update(profile_options) with MemoryFile() as mem_dst: cog_translate( src_path, mem_dst.name, output_profile, config=config, in_memory=False, # Limit Memory usage quiet=True, allow_intermediate_compression=True, # Limit Disk usage **options, ) _upload_obj(mem_dst, out_bucket, out_key) del mem_dst if not allow_remote_read: os.remove(src_path) return
def create( input, output, bidx, cogeo_profile, nodata, dtype, add_mask, overview_level, overview_resampling, overview_blocksize, web_optimized, latitude_adjustment, resampling, in_memory, allow_intermediate_compression, forward_band_tags, threads, creation_options, quiet, ): """Create Cloud Optimized Geotiff.""" if latitude_adjustment is not None and not web_optimized: warnings.warn( "'latitude_adjustment' option has to be used with --web-optimized options. " "Will be ignored.") output_profile = cog_profiles.get(cogeo_profile) output_profile.update(dict(BIGTIFF=os.environ.get("BIGTIFF", "IF_SAFER"))) if creation_options: output_profile.update(creation_options) config = dict( GDAL_NUM_THREADS=threads, GDAL_TIFF_INTERNAL_MASK=os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), GDAL_TIFF_OVR_BLOCKSIZE=str(overview_blocksize), ) cog_translate( input, output, output_profile, indexes=bidx, nodata=nodata, dtype=dtype, add_mask=add_mask, overview_level=overview_level, overview_resampling=overview_resampling, web_optimized=web_optimized, latitude_adjustment=latitude_adjustment, resampling=resampling, in_memory=in_memory, config=config, allow_intermediate_compression=allow_intermediate_compression, forward_band_tags=forward_band_tags, quiet=quiet, )
def convert_to_cog(raster, out_path=None, validate=True, **kwargs): output_profile = cog_profiles.get("deflate") if out_path is None: out_path = str(raster.with_suffix(".tif")).replace(" ", "_") assert raster != out_path, "Can't convert to files of the same name" cog_translate(raster, out_path, output_profile, quiet=True, **kwargs) if validate: cog_validate(out_path) return pathlib.Path(out_path)
def test_cog_translate_web(): """ Test Web-Optimized COG. - Test COG size is a multiple of 256 (mercator tile size) - Test COG bounds are aligned with mercator grid at max zoom """ runner = CliRunner() with runner.isolated_filesystem(): web_profile = cog_profiles.get("raw") web_profile.update({"blockxsize": 256, "blockysize": 256}) config = dict(GDAL_TIFF_OVR_BLOCKSIZE="128") cog_translate( raster_path_web, "cogeo.tif", web_profile, quiet=True, web_optimized=True, config=config, ) with rasterio.open(raster_path_web) as src_dst: with rasterio.open("cogeo.tif") as out_dst: blocks = list(set(out_dst.block_shapes)) assert len(blocks) == 1 ts = blocks[0][0] assert not out_dst.width % ts assert not out_dst.height % ts max_zoom = get_max_zoom(out_dst) bounds = list( transform_bounds( *[src_dst.crs, "epsg:4326"] + list(src_dst.bounds), densify_pts=21 ) ) leftTile = mercantile.tile(bounds[0], bounds[3], max_zoom) tbounds = mercantile.xy_bounds(leftTile) west, north = tbounds.left, tbounds.top assert out_dst.transform.xoff == west assert out_dst.transform.yoff == north rightTile = mercantile.tile(bounds[2], bounds[1], max_zoom) tbounds = mercantile.xy_bounds(rightTile) east, south = tbounds.right, tbounds.bottom lrx = round( out_dst.transform.xoff + out_dst.transform.a * out_dst.width, 6 ) lry = round( out_dst.transform.yoff + out_dst.transform.e * out_dst.height, 6 ) assert lrx == round(east, 6) assert lry == round(south, 6)
def test_profiles_ycbcr(): """Should work as expected (return ycbcr profile and raise warning).""" with pytest.warns(DeprecationWarning): profile = cog_profiles.get("ycbcr") assert profile["tiled"] assert profile["compress"] == "JPEG" assert profile["blockxsize"] == 512 assert profile["blockysize"] == 512 assert profile["photometric"] == "YCbCr" assert profile["interleave"] == "pixel"
def test_gdal_cog(src_path, runner): """Test GDAL COG.""" with runner.isolated_filesystem(): cog_translate( src_path, "cogeo.tif", cog_profiles.get("raw"), quiet=True, use_cog_driver=True, ) assert cog_validate("cogeo.tif")
def generate_cog(sourcefile, options={}): try: # Create GTiff from source gtiff_translate_output = f"{sourcefile}.tif" sourcefile_format = 'NETCDF' sourcefile_bandname = options.get('bandname') command = "gdal_translate" input_arg = f"{sourcefile_format}:{sourcefile}:{sourcefile_bandname}" output_arg = f"-of GTiff {gtiff_translate_output}" os.system(f"{command} {input_arg} {output_arg}") # Reproject GeoTiff reprojected_geotiff = f"{sourcefile}_reprojected.tif" command = "gdalwarp" input_arg = gtiff_translate_output target_spatial_reference = '+proj=longlat +ellps=WGS84' output_arg = f"{reprojected_geotiff} -t_srs '{target_spatial_reference}'" os.system(f"{command} {input_arg} {output_arg}") # Create Cloud-Optimized GTiff MAX_THREADS = int( os.environ.get("MAX_THREADS", multiprocessing.cpu_count() * 5)) in_tif = os.path.join(reprojected_geotiff) out_cog = os.path.join(f"{sourcefile}.cog.tif") config = dict( NUM_THREADS=MAX_THREADS, GDAL_TIFF_OVR_BLOCKSIZE=os.environ.get("GDAL_TIFF_OVR_BLOCKSIZE", "128"), ) source = rasterio.open(in_tif) profile = cog_profiles.get("deflate") profile.update({"blockxsize": 256, "blockysize": 256}) nodatavalue = numpy.nan if numpy.isnan( source.nodatavals[0]) else source.nodatavals[0] cog_translate(in_tif, out_cog, profile, nodata=nodatavalue, overview_resampling="bilinear", config=config, quiet=True) # Cleanup os.system(f"rm {gtiff_translate_output}") os.system(f"rm {reprojected_geotiff}") return out_cog except Exception as err: print(f"Caught exception {err}\n") return None