├── aligncheck ├── scripts │ ├── __init__.py │ └── cli.py └── __init__.py ├── .gitignore ├── HISTORY.txt ├── tests ├── data │ └── float.tif └── test_cli.py ├── README.rst ├── LICENSE └── setup.py /aligncheck/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pyc 3 | -------------------------------------------------------------------------------- /HISTORY.txt: -------------------------------------------------------------------------------- 1 | 1.0.0 2 | ------------------ 3 | - First and probably the last release. 4 | -------------------------------------------------------------------------------- /tests/data/float.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fitnr/rio-aligncheck/master/tests/data/float.tif -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | rio-aligncheck 2 | ================== 3 | 4 | A Rasterio command-line plugin to check raster alignment. 5 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from click.testing import CliRunner 3 | from aligncheck.scripts.cli import aligncheck 4 | 5 | 6 | def test_cli(): 7 | """A random item is printed.""" 8 | pass 9 | 10 | 11 | def test_cli_dtype(): 12 | """The dtype item is printed.""" 13 | pass 14 | -------------------------------------------------------------------------------- /aligncheck/scripts/cli.py: -------------------------------------------------------------------------------- 1 | import click 2 | from .. import check_alignment 3 | from .. import __version__ as aligncheck_version 4 | 5 | 6 | @click.command(short_help="Check raster alignment.") 7 | @click.argument('inputfiles', type=click.Path(resolve_path=True), required=True, 8 | nargs=-1, metavar="INPUT") 9 | @click.option('--report/--no-report', default=False) 10 | @click.option('--full-report/--no-full-report', default=False) 11 | @click.option('--header/--no-header', default=True) 12 | @click.version_option(version=aligncheck_version, message='%(version)s') 13 | @click.pass_context 14 | def aligncheck(_, inputfiles, report, full_report, header): 15 | """ 16 | Check if input rasters are aligned. 17 | """ 18 | kwargs = dict(report=report, full_report=full_report, header=header) 19 | result = check_alignment(inputfiles, **kwargs) 20 | 21 | if result: 22 | for row in result: 23 | click.echo(row) 24 | else: 25 | click.echo('aligned') 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Neil Freeman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from codecs import open as codecs_open 2 | from setuptools import setup, find_packages 3 | 4 | 5 | # Parse the version from the fiona module. 6 | with open('aligncheck/__init__.py') as f: 7 | for line in f: 8 | if line.find("__version__") >= 0: 9 | version = line.split("=")[1].strip().strip('"\'') 10 | break 11 | 12 | # Get the long description from the relevant file 13 | with codecs_open('README.rst', encoding='utf-8') as f: 14 | long_description = f.read() 15 | 16 | 17 | setup(name='rio-aligncheck', 18 | version=version, 19 | description=u"Rasterio CLI plugin for checking raster alignment", 20 | long_description=long_description, 21 | classifiers=[], 22 | keywords='', 23 | author=u"Neil Freeman", 24 | author_email='contact@fakeisthenewreal.org', 25 | url='https://github.com/fitnr/rio-aligncheck', 26 | license='BSD', 27 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), 28 | include_package_data=True, 29 | zip_safe=False, 30 | install_requires=[ 31 | 'click', 32 | 'rasterio' 33 | ], 34 | extras_require={ 35 | 'test': ['pytest'], 36 | }, 37 | entry_points=""" 38 | [rasterio.rio_commands] 39 | aligncheck=aligncheck.scripts.cli:aligncheck 40 | """) 41 | -------------------------------------------------------------------------------- /aligncheck/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import rasterio 4 | from affine import UndefinedRotationError 5 | 6 | __author__ = "Neil Freeman" 7 | __version__ = '1.0.0' 8 | 9 | HEADER = "path", "epsg", "origin-x", "origin-y", "pixelsize-x", "pixelsize-y" 10 | ROWFORMAT = "{path}\t{0[epsg]}\t{0[origin][0]}\t{0[origin][1]}\t{0[pixel size][0]}\t{0[pixel size][1]}" 11 | 12 | 13 | def get_meta(raster): 14 | with rasterio.open(raster) as src: 15 | return { 16 | 'epsg': src.profile['crs'].to_epsg(), 17 | 'origin': ( 18 | src.transform.xoff / src.transform[0], 19 | src.transform.yoff / -src.transform[4] 20 | ), 21 | 'pixel size': (src.transform[0], -src.transform[4]), 22 | } 23 | 24 | 25 | def check_alignment(rasters, **kwargs): 26 | metas = {raster: get_meta(raster) for raster in rasters} 27 | result = [] 28 | 29 | keys = 'epsg', 'origin', 'pixel size' 30 | 31 | if kwargs.get('full_report'): 32 | if kwargs.get('header'): 33 | result.append("\t".join(HEADER)) 34 | 35 | for path, m in metas.items(): 36 | result.append(ROWFORMAT.format(m, path=path)) 37 | 38 | elif kwargs.get('report'): 39 | distinct = [ 40 | dict(d) for d in 41 | list(set([tuple((k, m[k]) for k in keys) for m in metas.values()])) 42 | ] 43 | for path, m in metas.items(): 44 | for d in distinct: 45 | if all(d[k] == m[k] for k in keys): 46 | result.append('{}\t{}'.format(1 + distinct.index(d), path)) 47 | break 48 | 49 | else: 50 | for k in keys: 51 | attrs = set([m[k] for m in metas.values()]) 52 | if len(attrs) > 1: 53 | result.append('{} count: {}'.format(k, len(attrs))) 54 | 55 | return result 56 | --------------------------------------------------------------------------------