├── docs ├── docs │ ├── index.md │ ├── release-notes.md │ ├── contributing.md │ └── css │ │ └── extra.css └── mkdocs.yml ├── tests ├── __init__.py ├── fixtures │ ├── slc.tif │ ├── image_51px.tif │ ├── image_geos.tif │ ├── image_nan.tif │ ├── image_rgb.tif │ ├── image_rgba.tif │ ├── image_tags.tif │ ├── image_web.tif │ ├── cog_band_tags.tif │ ├── image_171px.tif │ ├── image_2000px.tif │ ├── image_float.tif │ ├── image_nodata.tif │ ├── image_north.tif │ ├── image_colormap.tif │ ├── image_rgb_mask.tif │ ├── image_nocolormap.tif │ ├── image_web_z5_z11.tif │ ├── image_with_offsets.tif │ └── image_missing_nodata.tif └── test_cli.py ├── rio_faux ├── __init__.py └── cli.py ├── .github ├── codecov.yml └── workflows │ ├── deploy_mkdocs.yml │ └── ci.yml ├── .bumpversion.cfg ├── CHANGES.md ├── .pre-commit-config.yaml ├── CONTRIBUTING.md ├── LICENSE ├── .gitignore ├── pyproject.toml └── README.md /docs/docs/index.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /docs/docs/release-notes.md: -------------------------------------------------------------------------------- 1 | ../../CHANGES.md -------------------------------------------------------------------------------- /docs/docs/contributing.md: -------------------------------------------------------------------------------- 1 | ../../CONTRIBUTING.md -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """rio-cogeo tests suite.""" 2 | -------------------------------------------------------------------------------- /rio_faux/__init__.py: -------------------------------------------------------------------------------- 1 | """Create empty copy of an image.""" 2 | 3 | __version__ = "0.2.1" 4 | -------------------------------------------------------------------------------- /tests/fixtures/slc.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/slc.tif -------------------------------------------------------------------------------- /tests/fixtures/image_51px.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_51px.tif -------------------------------------------------------------------------------- /tests/fixtures/image_geos.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_geos.tif -------------------------------------------------------------------------------- /tests/fixtures/image_nan.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_nan.tif -------------------------------------------------------------------------------- /tests/fixtures/image_rgb.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_rgb.tif -------------------------------------------------------------------------------- /tests/fixtures/image_rgba.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_rgba.tif -------------------------------------------------------------------------------- /tests/fixtures/image_tags.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_tags.tif -------------------------------------------------------------------------------- /tests/fixtures/image_web.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_web.tif -------------------------------------------------------------------------------- /tests/fixtures/cog_band_tags.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/cog_band_tags.tif -------------------------------------------------------------------------------- /tests/fixtures/image_171px.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_171px.tif -------------------------------------------------------------------------------- /tests/fixtures/image_2000px.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_2000px.tif -------------------------------------------------------------------------------- /tests/fixtures/image_float.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_float.tif -------------------------------------------------------------------------------- /tests/fixtures/image_nodata.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_nodata.tif -------------------------------------------------------------------------------- /tests/fixtures/image_north.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_north.tif -------------------------------------------------------------------------------- /tests/fixtures/image_colormap.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_colormap.tif -------------------------------------------------------------------------------- /tests/fixtures/image_rgb_mask.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_rgb_mask.tif -------------------------------------------------------------------------------- /tests/fixtures/image_nocolormap.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_nocolormap.tif -------------------------------------------------------------------------------- /tests/fixtures/image_web_z5_z11.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_web_z5_z11.tif -------------------------------------------------------------------------------- /tests/fixtures/image_with_offsets.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_with_offsets.tif -------------------------------------------------------------------------------- /tests/fixtures/image_missing_nodata.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cogeotiff/rio-faux/HEAD/tests/fixtures/image_missing_nodata.tif -------------------------------------------------------------------------------- /docs/docs/css/extra.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --md-primary-fg-color: #231b4e;; 3 | --md-primary-fg-color--light: #8782a3; 4 | --md-primary-fg-color--dark: #3b3750; 5 | } 6 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | comment: off 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 5 9 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.2.1 3 | commit = True 4 | tag = True 5 | tag_name = {new_version} 6 | 7 | [bumpversion:file:rio_faux/__init__.py] 8 | search = __version__ = "{current_version}" 9 | replace = __version__ = "{new_version}" 10 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # Release Notes 2 | 3 | ## 0.2.1 (2023-04-13) 4 | 5 | * Fix issue with CLI path 6 | * add Alpha band value forwarding 7 | * add `--value` option to set a custom value in the data 8 | 9 | ## 0.2.0 (2022-10-25) 10 | 11 | * remove python 3.7 support 12 | * add python 3.10 and 3.11 support 13 | 14 | ## 0.1.1 (2022-07-21) 15 | 16 | * disable dataset `tags` forwarding by default and add `--forward-dataset-tags` options 17 | * band descriptions are only forwarded if `--forward-band-tags` is set 18 | 19 | ## 0.1.0 (2022-07-21) 20 | 21 | * Initial release. 22 | -------------------------------------------------------------------------------- /.github/workflows/deploy_mkdocs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs via GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | # Only rebuild website when docs have changed 9 | - 'README.md' 10 | - 'CHANGES.md' 11 | - 'CONTRIBUTING.md' 12 | - 'docs/**' 13 | 14 | jobs: 15 | build: 16 | name: Deploy docs 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout master 20 | uses: actions/checkout@v2 21 | 22 | - name: Set up Python 3.8 23 | uses: actions/setup-python@v2 24 | with: 25 | python-version: 3.8 26 | 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install -e .["docs"] 31 | 32 | - name: Deploy docs 33 | run: mkdocs gh-deploy -f docs/mkdocs.yml --force 34 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/abravalheri/validate-pyproject 3 | rev: v0.12.1 4 | hooks: 5 | - id: validate-pyproject 6 | 7 | - repo: https://github.com/psf/black 8 | rev: 22.12.0 9 | hooks: 10 | - id: black 11 | language_version: python 12 | 13 | - repo: https://github.com/PyCQA/isort 14 | rev: 5.12.0 15 | hooks: 16 | - id: isort 17 | language_version: python 18 | 19 | - repo: https://github.com/charliermarsh/ruff-pre-commit 20 | rev: v0.0.238 21 | hooks: 22 | - id: ruff 23 | args: ["--fix"] 24 | 25 | - repo: https://github.com/pre-commit/mirrors-mypy 26 | rev: v0.991 27 | hooks: 28 | - id: mypy 29 | language_version: python 30 | # No reason to run if only tests have changed. They intentionally break typing. 31 | exclude: tests/.* 32 | additional_dependencies: 33 | - types-attrs 34 | - types-cachetools 35 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Issues and pull requests are more than welcome. 4 | 5 | **dev install** 6 | 7 | ```bash 8 | $ git clone https://github.com/cogeotiff/rio-faux.git 9 | $ cd rio-faux 10 | $ pip install -e .["test","dev"] 11 | ``` 12 | You can then run the tests with the following command: 13 | 14 | ```sh 15 | python -m pytest --cov rio_faux --cov-report term-missing 16 | ``` 17 | 18 | ## pre-commit 19 | 20 | This repo is set to use `pre-commit` to run *isort*, *flake8*, *pydocstring*, *black* ("uncompromising Python code formatter") and mypy when committing new code. 21 | 22 | ```bash 23 | $ pre-commit install 24 | ``` 25 | 26 | ## Docs 27 | 28 | ```bash 29 | $ git clone https://github.com/cogeotiff/rio-faux.git 30 | $ cd rio-faux 31 | $ pip install -e .["docs"] 32 | ``` 33 | 34 | Hot-reloading docs: 35 | 36 | ```bash 37 | $ mkdocs serve 38 | ``` 39 | 40 | To manually deploy docs (note you should never need to do this because Github 41 | Actions deploys automatically for new commits.): 42 | 43 | ```bash 44 | $ mkdocs gh-deploy 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: rio-faux 2 | site_description: Create empty image from a model. 3 | 4 | repo_name: 'cogeotiff/rio-faux' 5 | repo_url: 'https://github.com/cogeotiff/rio-faux' 6 | edit_uri: 'blob/master/docs/docs/' 7 | site_url: 'https://cogeotiff.github.io/rio-faux/' 8 | 9 | extra: 10 | social: 11 | - icon: 'fontawesome/brands/github' 12 | link: 'https://github.com/cogeotiff' 13 | - icon: 'fontawesome/brands/twitter' 14 | link: 'https://twitter.com/cogeotiff' 15 | - icon: 'fontawesome/solid/globe' 16 | link: 'https://www.cogeo.org/' 17 | 18 | nav: 19 | - Home: "index.md" 20 | - Development - Contributing: "contributing.md" 21 | - Release Notes: "release-notes.md" 22 | 23 | plugins: 24 | - search 25 | 26 | theme: 27 | name: material 28 | palette: 29 | scheme: default 30 | 31 | extra_css: 32 | - css/extra.css 33 | 34 | # https://github.com/kylebarron/cogeo-mosaic/blob/mkdocs/mkdocs.yml#L50-L75 35 | markdown_extensions: 36 | - admonition 37 | - attr_list 38 | - codehilite: 39 | guess_lang: false 40 | - def_list 41 | - footnotes 42 | - pymdownx.arithmatex 43 | - pymdownx.betterem 44 | - pymdownx.caret: 45 | insert: false 46 | - pymdownx.details 47 | - pymdownx.emoji 48 | - pymdownx.escapeall: 49 | hardbreak: true 50 | nbsp: true 51 | - pymdownx.magiclink: 52 | hide_protocol: true 53 | repo_url_shortener: true 54 | - pymdownx.smartsymbols 55 | - pymdownx.superfences 56 | - pymdownx.tasklist: 57 | custom_checkbox: true 58 | - pymdownx.tilde 59 | - toc: 60 | permalink: true 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, cogeotiff 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | .pytest_cache 104 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "rio-faux" 3 | description = "Create empty image from a model." 4 | readme = "README.md" 5 | requires-python = ">=3.8" 6 | license = {file = "LICENSE"} 7 | authors = [ 8 | {name = "Vincent Sarago", email = "vincent@developmentseed.com"}, 9 | ] 10 | keywords = ["rasterio"] 11 | classifiers = [ 12 | "Intended Audience :: Information Technology", 13 | "Intended Audience :: Science/Research", 14 | "License :: OSI Approved :: BSD License", 15 | "Programming Language :: Python :: 3.8", 16 | "Programming Language :: Python :: 3.9", 17 | "Programming Language :: Python :: 3.10", 18 | "Programming Language :: Python :: 3.11", 19 | "Topic :: Scientific/Engineering :: GIS", 20 | ] 21 | dynamic = ["version"] 22 | dependencies = [ 23 | "click>=7.0", 24 | "rasterio>=1.1", 25 | ] 26 | 27 | [project.optional-dependencies] 28 | test = [ 29 | "pytest", 30 | "pytest-cov", 31 | ] 32 | dev = [ 33 | "pre-commit", 34 | ] 35 | docs = [ 36 | "mkdocs", 37 | "mkdocs-material", 38 | ] 39 | 40 | [project.urls] 41 | Source = "https://github.com/cogeotiff/rio-faux" 42 | Documentation = "https://cogeotiff.github.io/rio-faux/" 43 | 44 | [project.entry-points."rasterio.rio_plugins"] 45 | faux = "rio_faux.cli:faux" 46 | 47 | [build-system] 48 | requires = ["flit>=3.2,<4"] 49 | build-backend = "flit_core.buildapi" 50 | 51 | [tool.flit.module] 52 | name = "rio_faux" 53 | 54 | [tool.flit.sdist] 55 | exclude = [ 56 | "tests/", 57 | "docs/", 58 | ".github/", 59 | "CHANGES.md", 60 | "codecov.yml", 61 | "CONTRIBUTING.md", 62 | "mkdocs.yml", 63 | ] 64 | 65 | [tool.coverage.run] 66 | branch = true 67 | parallel = true 68 | 69 | [tool.coverage.report] 70 | exclude_lines = [ 71 | "no cov", 72 | "if __name__ == .__main__.:", 73 | "if TYPE_CHECKING:", 74 | ] 75 | 76 | [tool.isort] 77 | profile = "black" 78 | known_first_party = ["rio_fake"] 79 | known_third_party = ["rasterio", "click"] 80 | default_section = "THIRDPARTY" 81 | 82 | [tool.mypy] 83 | no_strict_optional = true 84 | 85 | [tool.ruff] 86 | select = [ 87 | "D1", # pydocstyle errors 88 | "E", # pycodestyle errors 89 | "W", # pycodestyle warnings 90 | "C", # flake8-comprehensions 91 | "B", # flake8-bugbear 92 | ] 93 | ignore = [ 94 | "E501", # line too long, handled by black 95 | "B008", # do not perform function calls in argument defaults 96 | "B905", # ignore zip() without an explicit strict= parameter, only support with python >3.10 97 | ] 98 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | # On every pull request, but only on push to master 4 | on: 5 | push: 6 | branches: 7 | - main 8 | tags: 9 | - '*' 10 | pull_request: 11 | env: 12 | LATEST_PY_VERSION: '3.10' 13 | 14 | jobs: 15 | tests: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | python-version: 20 | - '3.8' 21 | - '3.9' 22 | - '3.10' 23 | - '3.11.0-rc.2 - 3.11' 24 | 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Set up Python ${{ matrix.python-version }} 28 | uses: actions/setup-python@v2 29 | with: 30 | python-version: ${{ matrix.python-version }} 31 | 32 | - name: Install dependencies 33 | run: | 34 | python -m pip install --upgrade pip 35 | python -m pip install .["test"] 36 | 37 | - name: Run test 38 | run: python -m pytest --cov rio_faux --cov-report xml --cov-report term-missing 39 | 40 | - name: run pre-commit 41 | if: ${{ matrix.python-version == env.LATEST_PY_VERSION }} 42 | run: | 43 | python -m pip install pre-commit 44 | pre-commit run --all-files 45 | 46 | - name: Upload Results 47 | if: ${{ matrix.python-version == env.LATEST_PY_VERSION }} 48 | uses: codecov/codecov-action@v1 49 | with: 50 | file: ./coverage.xml 51 | flags: unittests 52 | name: ${{ matrix.python-version }} 53 | fail_ci_if_error: false 54 | 55 | publish: 56 | needs: [tests] 57 | runs-on: ubuntu-latest 58 | if: startsWith(github.event.ref, 'refs/tags') || github.event_name == 'release' 59 | steps: 60 | - uses: actions/checkout@v2 61 | - name: Set up Python 62 | uses: actions/setup-python@v1 63 | with: 64 | python-version: ${{ env.LATEST_PY_VERSION }} 65 | 66 | - name: Install dependencies 67 | run: | 68 | python -m pip install --upgrade pip 69 | python -m pip install flit 70 | python -m pip install . 71 | 72 | - name: Set tag version 73 | id: tag 74 | # https://stackoverflow.com/questions/58177786/get-the-current-pushed-tag-in-github-actions 75 | run: echo ::set-output name=tag::${GITHUB_REF#refs/*/} 76 | 77 | - name: Set module version 78 | id: module 79 | # https://stackoverflow.com/questions/58177786/get-the-current-pushed-tag-in-github-actions 80 | run: echo ::set-output name=version::$(python -c 'from importlib.metadata import version; print(version("rio_faux"))') 81 | 82 | - name: Build and publish 83 | if: steps.tag.outputs.tag == steps.module.outputs.version 84 | env: 85 | FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }} 86 | FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 87 | run: flit publish 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rio-faux 2 | 3 |

4 | rio-tiler 5 |

6 |

7 | Now you can share your dataset! 8 |

9 | 10 |

11 | 12 | Test 13 | 14 | 15 | Coverage 16 | 17 | 18 | Package version 19 | 20 | 21 | Downloads 22 | 23 | 24 | Downloads 25 | 26 |

27 | 28 | --- 29 | 30 | **Documentation**: https://cogeotiff.github.io/rio-faux/ 31 | 32 | **Source Code**: https://github.com/cogeotiff/rio-faux 33 | 34 | --- 35 | 36 | Create a copy of your dataset without copying the data. 37 | 38 | ## Install 39 | 40 | ```bash 41 | $ pip install -U pip 42 | $ pip install rio-faux 43 | ``` 44 | 45 | Or install from source: 46 | 47 | ```bash 48 | $ pip install -U pip 49 | $ pip install git+https://github.com/cogeotiff/rio-faux.git 50 | ``` 51 | 52 | ## Usage 53 | 54 | ``` 55 | $ rio faux --help 56 | Usage: rio faux [OPTIONS] INPUT OUTPUT 57 | 58 | Create empty copy. 59 | 60 | Options: 61 | --forward-band-tags Forward band tags to output bands. 62 | --forward-dataset-tags Forward dataset tags to output image. 63 | --co, --profile NAME=VALUE Driver specific creation options. See the documentation for the selected output driver for more information. 64 | --config NAME=VALUE GDAL configuration options. 65 | --help Show this message and exit. 66 | ``` 67 | 68 | ``` 69 | $ rio faux tests/fixtures/cog_band_tags.tif out.tif 70 | ``` 71 | ![](https://user-images.githubusercontent.com/10407788/180162026-2a023aa9-9c1b-4277-a3c2-c2865d9d7c43.png) 72 | 73 | 74 | ## Contribution & Development 75 | 76 | See [CONTRIBUTING.md](https://github.com/cogeotiff/rio-faux/blob/master/CONTRIBUTING.md) 77 | 78 | ## Changes 79 | 80 | See [CHANGES.md](https://github.com/cogeotiff/rio-faux/blob/master/CHANGES.md). 81 | 82 | ## License 83 | 84 | See [LICENSE](https://github.com/cogeotiff/rio-faux/blob/master/LICENSE) 85 | 86 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | """test rio-faux.""" 2 | 3 | import math 4 | import os 5 | 6 | import numpy 7 | import pytest 8 | import rasterio 9 | from click.testing import CliRunner 10 | 11 | from rio_faux.cli import faux 12 | 13 | files = [ 14 | "cog_band_tags.tif", 15 | "image_171px.tif", 16 | "image_2000px.tif", 17 | "image_51px.tif", 18 | "image_colormap.tif", 19 | "image_float.tif", 20 | "image_geos.tif", 21 | "image_missing_nodata.tif", 22 | "image_nan.tif", 23 | "image_nocolormap.tif", 24 | "image_nodata.tif", 25 | "image_north.tif", 26 | "image_rgb.tif", 27 | "image_rgb_mask.tif", 28 | "image_rgba.tif", 29 | "image_tags.tif", 30 | "image_web.tif", 31 | "image_web_z5_z11.tif", 32 | "image_with_offsets.tif", 33 | "slc.tif", 34 | ] 35 | 36 | 37 | @pytest.mark.parametrize("input", files) 38 | def test_cli(input): 39 | """Check equivalence of profiles""" 40 | runner = CliRunner() 41 | src_path = os.path.join(os.path.dirname(__file__), "fixtures", input) 42 | with runner.isolated_filesystem(): 43 | result = runner.invoke(faux, [src_path, "output.tif"]) 44 | assert not result.exception 45 | assert result.exit_code == 0 46 | with rasterio.open(src_path) as src_dst, rasterio.open( 47 | "output.tif" 48 | ) as faux_dst: 49 | src_p = src_dst.profile 50 | faux_p = faux_dst.profile 51 | 52 | if src_p["nodata"] is not None and not math.isfinite(src_p["nodata"]): 53 | assert not math.isfinite(faux_p["nodata"]) 54 | src_p.pop("nodata") 55 | faux_p.pop("nodata") 56 | 57 | assert src_p == faux_p 58 | 59 | 60 | def test_tags(): 61 | """Check if tags are forwarded.""" 62 | runner = CliRunner() 63 | src_path = os.path.join(os.path.dirname(__file__), "fixtures", "cog_band_tags.tif") 64 | with runner.isolated_filesystem(): 65 | result = runner.invoke(faux, [src_path, "output.tif"]) 66 | assert not result.exception 67 | assert result.exit_code == 0 68 | with rasterio.open(src_path) as src_dst, rasterio.open( 69 | "output.tif" 70 | ) as faux_dst: 71 | assert src_dst.profile == faux_dst.profile 72 | assert not src_dst.tags() == faux_dst.tags() 73 | assert not src_dst.descriptions == faux_dst.descriptions 74 | assert not src_dst.tags(0) == faux_dst.tags(0) 75 | 76 | result = runner.invoke( 77 | faux, 78 | [src_path, "output.tif", "--forward-band-tags", "--forward-dataset-tags"], 79 | ) 80 | assert not result.exception 81 | assert result.exit_code == 0 82 | with rasterio.open(src_path) as src_dst, rasterio.open( 83 | "output.tif" 84 | ) as faux_dst: 85 | assert src_dst.profile == faux_dst.profile 86 | assert src_dst.tags() == faux_dst.tags() 87 | assert src_dst.descriptions == faux_dst.descriptions 88 | assert src_dst.tags(0) == faux_dst.tags(0) 89 | 90 | 91 | def test_alpha(): 92 | """Check if alpha forwarded.""" 93 | runner = CliRunner() 94 | src_path = os.path.join(os.path.dirname(__file__), "fixtures", "image_rgba.tif") 95 | with runner.isolated_filesystem(): 96 | result = runner.invoke(faux, [src_path, "output.tif"]) 97 | assert not result.exception 98 | assert result.exit_code == 0 99 | with rasterio.open(src_path) as src_dst, rasterio.open( 100 | "output.tif" 101 | ) as faux_dst: 102 | assert src_dst.colorinterp == faux_dst.colorinterp 103 | numpy.testing.assert_array_equal( 104 | src_dst.read(indexes=4), faux_dst.read(indexes=4) 105 | ) 106 | 107 | 108 | def test_mask(): 109 | """Check if alpha forwarded.""" 110 | runner = CliRunner() 111 | src_path = os.path.join(os.path.dirname(__file__), "fixtures", "image_rgb_mask.tif") 112 | with runner.isolated_filesystem(): 113 | result = runner.invoke(faux, [src_path, "output.tif"]) 114 | assert not result.exception 115 | assert result.exit_code == 0 116 | with rasterio.open(src_path) as src_dst, rasterio.open( 117 | "output.tif" 118 | ) as faux_dst: 119 | assert src_dst.mask_flag_enums == faux_dst.mask_flag_enums 120 | numpy.testing.assert_array_equal( 121 | src_dst.dataset_mask(), faux_dst.dataset_mask() 122 | ) 123 | 124 | 125 | def test_value(): 126 | """Check value.""" 127 | runner = CliRunner() 128 | src_path = os.path.join(os.path.dirname(__file__), "fixtures", "image_rgba.tif") 129 | with runner.isolated_filesystem(): 130 | result = runner.invoke(faux, [src_path, "output.tif", "--value", 100]) 131 | assert not result.exception 132 | assert result.exit_code == 0 133 | with rasterio.open(src_path) as src_dst, rasterio.open( 134 | "output.tif" 135 | ) as faux_dst: 136 | 137 | assert numpy.unique(faux_dst.read(indexes=1)) == 100 138 | 139 | # Check that we are casting values to the output data type 140 | result = runner.invoke(faux, [src_path, "output.tif", "--value", 100.3]) 141 | assert not result.exception 142 | assert result.exit_code == 0 143 | with rasterio.open(src_path) as src_dst, rasterio.open( 144 | "output.tif" 145 | ) as faux_dst: 146 | 147 | assert numpy.unique(faux_dst.read(indexes=1)) == 100 148 | -------------------------------------------------------------------------------- /rio_faux/cli.py: -------------------------------------------------------------------------------- 1 | """rio-faux.""" 2 | 3 | import os 4 | import warnings 5 | 6 | import click 7 | import numpy 8 | import rasterio 9 | from rasterio.enums import ColorInterp, MaskFlags 10 | from rasterio.enums import Resampling as ResamplingEnums 11 | from rasterio.io import MemoryFile 12 | from rasterio.rio import options 13 | from rasterio.shutil import copy 14 | 15 | 16 | def has_mask_band(src_dst): 17 | """Check for mask band in source.""" 18 | if any( 19 | [ 20 | (MaskFlags.per_dataset in flags and MaskFlags.alpha not in flags) 21 | for flags in src_dst.mask_flag_enums 22 | ] 23 | ): 24 | return True 25 | return False 26 | 27 | 28 | @click.command() 29 | @options.file_in_arg 30 | @options.file_out_arg 31 | @click.option( 32 | "--value", 33 | default=None, 34 | type=float, 35 | help="Set a custom value in the data.", 36 | ) 37 | @click.option( 38 | "--forward-band-tags", 39 | default=False, 40 | is_flag=True, 41 | help="Forward band tags to output bands.", 42 | ) 43 | @click.option( 44 | "--forward-dataset-tags", 45 | default=False, 46 | is_flag=True, 47 | help="Forward dataset tags to output image.", 48 | ) 49 | @options.creation_options 50 | @click.option( 51 | "--config", 52 | "config", 53 | metavar="NAME=VALUE", 54 | multiple=True, 55 | callback=options._cb_key_val, 56 | help="GDAL configuration options.", 57 | ) 58 | def faux( 59 | input, 60 | output, 61 | value, 62 | forward_band_tags, 63 | forward_dataset_tags, 64 | creation_options, 65 | config, 66 | ): 67 | """Create empty copy.""" 68 | # Check if the dataset has overviews 69 | with rasterio.open(input) as src_dst: 70 | ovr = src_dst.overviews(1) 71 | 72 | # Get Overview Blocksize 73 | overview_blocksize = 512 74 | if ovr: 75 | with rasterio.open(input, OVERVIEW_LEVEL=0) as src_dst: 76 | overview_blocksize = src_dst.profile.get("blockxsize", overview_blocksize) 77 | 78 | config.update( 79 | { 80 | "GDAL_NUM_THREADS": "ALL_CPUS", 81 | "GDAL_TIFF_INTERNAL_MASK": os.environ.get("GDAL_TIFF_INTERNAL_MASK", True), 82 | "GDAL_TIFF_OVR_BLOCKSIZE": str(overview_blocksize), 83 | } 84 | ) 85 | 86 | with rasterio.Env(**config): 87 | with rasterio.open(input) as src_dst: 88 | meta = src_dst.meta 89 | with MemoryFile() as m: 90 | with m.open(**meta) as tmp_dst: 91 | tmp_dst.colorinterp = src_dst.colorinterp 92 | 93 | if tmp_dst.colorinterp[0] is ColorInterp.palette: 94 | try: 95 | tmp_dst.write_colormap(1, src_dst.colormap(1)) 96 | except ValueError: 97 | warnings.warn( 98 | "Dataset has `Palette` color interpretation" 99 | " but is missing colormap information" 100 | ) 101 | 102 | if has_mask_band(src_dst): 103 | tmp_dst.write_mask(src_dst.dataset_mask()) 104 | 105 | if value: 106 | tmp_dst.write( 107 | numpy.full( 108 | (tmp_dst.count, tmp_dst.height, tmp_dst.width), 109 | value, 110 | dtype=tmp_dst.dtypes[0], 111 | ), 112 | ) 113 | 114 | if ColorInterp.alpha in tmp_dst.colorinterp: 115 | alpha_bidx = src_dst.colorinterp.index(ColorInterp.alpha) + 1 116 | tmp_dst.write( 117 | src_dst.read(indexes=alpha_bidx), 118 | indexes=alpha_bidx, 119 | ) 120 | 121 | tags = src_dst.tags() 122 | 123 | overview_resampling = tags.get( 124 | "OVR_RESAMPLING_ALG", "nearest" 125 | ).lower() 126 | if ovr: 127 | tmp_dst.build_overviews( 128 | ovr, ResamplingEnums[overview_resampling] 129 | ) 130 | 131 | indexes = src_dst.indexes 132 | 133 | if forward_band_tags: 134 | for i, b in enumerate(indexes): 135 | tmp_dst.set_band_description( 136 | i + 1, src_dst.descriptions[b - 1] 137 | ) 138 | tmp_dst.update_tags(i + 1, **src_dst.tags(b)) 139 | 140 | if forward_dataset_tags: 141 | tmp_dst.update_tags(**tags) 142 | 143 | tmp_dst._set_all_scales([src_dst.scales[b - 1] for b in indexes]) 144 | tmp_dst._set_all_offsets([src_dst.offsets[b - 1] for b in indexes]) 145 | 146 | output_profile = src_dst.profile 147 | output_profile.update( 148 | {"BIGTIFF": os.environ.get("BIGTIFF", "IF_SAFER")} 149 | ) 150 | if creation_options: 151 | output_profile.update(creation_options) 152 | 153 | keys = [ 154 | "dtype", 155 | "nodata", 156 | "width", 157 | "height", 158 | "count", 159 | "crs", 160 | "transform", 161 | ] 162 | for key in keys: 163 | output_profile.pop(key, None) 164 | 165 | copy(tmp_dst, output, copy_src_overviews=True, **output_profile) 166 | --------------------------------------------------------------------------------