viewtif 0.1.5__tar.gz → 0.1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- viewtif-0.1.7/.gitignore +8 -0
- viewtif-0.1.7/PKG-INFO +137 -0
- viewtif-0.1.7/README.md +117 -0
- viewtif-0.1.7/examples/sample_data/AG100.v003.13.-017.0001.h5 +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/pyproject.toml +2 -2
- {viewtif-0.1.5 → viewtif-0.1.7}/src/viewtif/tif_viewer.py +216 -44
- viewtif-0.1.5/.gitignore +0 -4
- viewtif-0.1.5/PKG-INFO +0 -93
- viewtif-0.1.5/README.md +0 -73
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/README.md +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/ECOSTRESS_LST.tif +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/HLS_B02.tif +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/HLS_B03.tif +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/HLS_B04.tif +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/Zip_Codes.cpg +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/Zip_Codes.dbf +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/Zip_Codes.prj +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/Zip_Codes.shp +0 -0
- {viewtif-0.1.5 → viewtif-0.1.7}/examples/sample_data/Zip_Codes.shx +0 -0
viewtif-0.1.7/.gitignore
ADDED
viewtif-0.1.7/PKG-INFO
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: viewtif
|
|
3
|
+
Version: 0.1.7
|
|
4
|
+
Summary: Lightweight GeoTIFF, HDF/HDF5, and Esri File Geodatabase (.gdb) viewer with shapefile overlay and large-raster safeguard.
|
|
5
|
+
Project-URL: Homepage, https://github.com/nkeikon/tifviewer
|
|
6
|
+
Project-URL: Source, https://github.com/nkeikon/tifviewer
|
|
7
|
+
Project-URL: Issues, https://github.com/nkeikon/tifviewer/issues
|
|
8
|
+
Author: Keiko Nomura
|
|
9
|
+
License: MIT
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Requires-Dist: click>=8.1
|
|
12
|
+
Requires-Dist: matplotlib>=3.7
|
|
13
|
+
Requires-Dist: numpy>=1.23
|
|
14
|
+
Requires-Dist: pyside6>=6.5
|
|
15
|
+
Requires-Dist: rasterio>=1.3
|
|
16
|
+
Provides-Extra: geo
|
|
17
|
+
Requires-Dist: geopandas>=0.13; extra == 'geo'
|
|
18
|
+
Requires-Dist: shapely>=2.0; extra == 'geo'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# viewtif
|
|
22
|
+
[](https://pepy.tech/project/viewtif)
|
|
23
|
+
[](https://pypi.org/project/viewtif/)
|
|
24
|
+
[](https://pypi.org/project/viewtif/)
|
|
25
|
+
|
|
26
|
+
A lightweight GeoTIFF viewer for quick visualization directly from the command line.
|
|
27
|
+
|
|
28
|
+
You can visualize single-band GeoTIFFs, RGB composites, and shapefile overlays in a simple Qt-based window.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install viewtif
|
|
36
|
+
```
|
|
37
|
+
> **Note:** On Linux, you may need python3-tk, libqt5gui5, or PySide6 dependencies.
|
|
38
|
+
>
|
|
39
|
+
>`viewtif` requires a graphical display environment.
|
|
40
|
+
> It may not run properly on headless systems (e.g., HPC compute nodes or remote servers without X11 forwarding).
|
|
41
|
+
|
|
42
|
+
### Optional features
|
|
43
|
+
#### Shapefile overlay support
|
|
44
|
+
```bash
|
|
45
|
+
pip install "viewtif[geo]"
|
|
46
|
+
```
|
|
47
|
+
> **Note:** For macOS(zsh) users:
|
|
48
|
+
> Make sure to include the quotes, or zsh will interpret it as a pattern.
|
|
49
|
+
|
|
50
|
+
#### HDF/HDF5 support
|
|
51
|
+
```bash
|
|
52
|
+
brew install gdal # macOS
|
|
53
|
+
sudo apt install gdal-bin python3-gdal # Linux
|
|
54
|
+
pip install GDAL
|
|
55
|
+
```
|
|
56
|
+
> **Note:** GDAL is required to open `.hdf`, .`h5`, and `.hdf5` files. If it’s missing, viewtif will display: `RuntimeError: HDF support requires GDAL.`
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
```bash
|
|
60
|
+
# View a GeoTIFF
|
|
61
|
+
viewtif ECOSTRESS_LST.tif
|
|
62
|
+
|
|
63
|
+
# View an RGB composite
|
|
64
|
+
viewtif --rgbfiles \
|
|
65
|
+
HLS_B04.tif \
|
|
66
|
+
HLS_B03.tif \
|
|
67
|
+
HLS_B02.tif
|
|
68
|
+
|
|
69
|
+
# View with shapefile overlay
|
|
70
|
+
viewtif ECOSTRESS_LST.tif \
|
|
71
|
+
--shapefile Zip_Codes.shp
|
|
72
|
+
```
|
|
73
|
+
### Update in v1.0.6: HDF/HDF5 support
|
|
74
|
+
`viewtif` can open `.hdf`, `.h5`, and `.hdf5` files that contain multiple subdatasets. When opened, it lists available subdatasets and lets you view one by index. You can also specify a band to display (default is the first band) or change bands interactively with '[' and ']'.
|
|
75
|
+
```bash
|
|
76
|
+
# List subdatasets
|
|
77
|
+
viewtif AG100.v003.33.-107.0001.h5
|
|
78
|
+
|
|
79
|
+
# View a specific subdataset
|
|
80
|
+
viewtif AG100.v003.33.-107.0001.h5 --subset 1
|
|
81
|
+
|
|
82
|
+
# View a specific subdataset and band
|
|
83
|
+
viewtif AG100.v003.33.-107.0001.h5 --subset 1 --band 3
|
|
84
|
+
```
|
|
85
|
+
> **Note:** Some datasets (perhaps the majority of .hdf files) lack CRS information encoded, so shapefile overlays may not work. In that case, viewtif will display:
|
|
86
|
+
`[WARN] raster lacks CRS/transform; cannot place overlays.`
|
|
87
|
+
|
|
88
|
+
### Update in v1.0.7: File Geodatabase (.gdb) support
|
|
89
|
+
`viewtif` can now open raster datasets stored inside Esri File Geodatabases (`.gdb`), using the GDAL `OpenFileGDB` driver.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Example
|
|
93
|
+
viewtif "OpenFileGDB:/path/to/geodatabase.gdb:RasterName"
|
|
94
|
+
```
|
|
95
|
+
> **Note:** Requires GDAL 3.7 or later with the OpenFileGDB driver enabled. The .gdb path and raster name must be separated by a colon (:).
|
|
96
|
+
|
|
97
|
+
### Update in v1.0.7: Large raster safeguard
|
|
98
|
+
As of v1.0.7, `viewtif` automatically checks the raster size before loading.
|
|
99
|
+
If the dataset is very large (e.g., >20 million pixels), it will pause and warn that loading may freeze your system.
|
|
100
|
+
You can proceed manually or rerun with the `--scale` option for a smaller, faster preview.
|
|
101
|
+
|
|
102
|
+
## Controls
|
|
103
|
+
| Key | Action |
|
|
104
|
+
| -------------------- | --------------------------------------- |
|
|
105
|
+
| `+` / `-` or mouse / trackpad | Zoom in / out |
|
|
106
|
+
| Arrow keys or `WASD` | Pan |
|
|
107
|
+
| `C` / `V` | Increase / decrease contrast |
|
|
108
|
+
| `G` / `H` | Increase / decrease gamma |
|
|
109
|
+
| `M` | Toggle colormap (`viridis` ↔ `magma`) |
|
|
110
|
+
| `[` / `]` | Previous / next band (single-band only) |
|
|
111
|
+
| `R` | Reset view |
|
|
112
|
+
|
|
113
|
+
## Features
|
|
114
|
+
- Command-line driven GeoTIFF viewer.
|
|
115
|
+
- Supports single-band, RGB composite, and HDF/HDF5 subdatasets.
|
|
116
|
+
- Optional shapefile overlay for geographic context.
|
|
117
|
+
- Adjustable contrast, gamma, and colormap.
|
|
118
|
+
- Fast preview using rasterio and PySide6.
|
|
119
|
+
|
|
120
|
+
## Example Data
|
|
121
|
+
- ECOSTRESS_LST.tif
|
|
122
|
+
- Zip_Codes.shp and associated files
|
|
123
|
+
- HLS_B04.tif, HLS_B03.tif, HLS_B02.tif (RGB sample)
|
|
124
|
+
- AG100.v003.33.-107.0001.h5 (HDF5 file)
|
|
125
|
+
|
|
126
|
+
## Credit & License
|
|
127
|
+
`viewtif` was inspired by the NASA JPL Thermal Viewer — Semi-Automated Georeferencer (GeoViewer v1.12) developed by Jake Longenecker (University of Miami Rosenstiel School of Marine, Atmospheric & Earth Science) while at the NASA Jet Propulsion Laboratory, California Institute of Technology, with inspiration from JPL’s ECOSTRESS geolocation batch workflow by Andrew Alamillo. The original GeoViewer was released under the MIT License (2025) and may be freely adapted with citation.
|
|
128
|
+
|
|
129
|
+
## Citation
|
|
130
|
+
Longenecker, Jake; Lee, Christine; Hulley, Glynn; Cawse-Nicholson, Kerry; Purkis, Sam; Gleason, Art; Otis, Dan; Galdamez, Ileana; Meiseles, Jacquelyn. GeoViewer v1.12: NASA JPL Thermal Viewer—Semi-Automated Georeferencer User Guide & Reference Manual. Jet Propulsion Laboratory, California Institute of Technology, 2025. PDF.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
This project is released under the MIT License.
|
|
134
|
+
|
|
135
|
+
## Contributors
|
|
136
|
+
- [@HarshShinde0](https://github.com/HarshShinde0) — added mouse-wheel and trackpad zoom support
|
|
137
|
+
- [@p-vdp](https://github.com/p-vdp) — added File Geodatabase (.gdb) raster support
|
viewtif-0.1.7/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# viewtif
|
|
2
|
+
[](https://pepy.tech/project/viewtif)
|
|
3
|
+
[](https://pypi.org/project/viewtif/)
|
|
4
|
+
[](https://pypi.org/project/viewtif/)
|
|
5
|
+
|
|
6
|
+
A lightweight GeoTIFF viewer for quick visualization directly from the command line.
|
|
7
|
+
|
|
8
|
+
You can visualize single-band GeoTIFFs, RGB composites, and shapefile overlays in a simple Qt-based window.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install viewtif
|
|
16
|
+
```
|
|
17
|
+
> **Note:** On Linux, you may need python3-tk, libqt5gui5, or PySide6 dependencies.
|
|
18
|
+
>
|
|
19
|
+
>`viewtif` requires a graphical display environment.
|
|
20
|
+
> It may not run properly on headless systems (e.g., HPC compute nodes or remote servers without X11 forwarding).
|
|
21
|
+
|
|
22
|
+
### Optional features
|
|
23
|
+
#### Shapefile overlay support
|
|
24
|
+
```bash
|
|
25
|
+
pip install "viewtif[geo]"
|
|
26
|
+
```
|
|
27
|
+
> **Note:** For macOS(zsh) users:
|
|
28
|
+
> Make sure to include the quotes, or zsh will interpret it as a pattern.
|
|
29
|
+
|
|
30
|
+
#### HDF/HDF5 support
|
|
31
|
+
```bash
|
|
32
|
+
brew install gdal # macOS
|
|
33
|
+
sudo apt install gdal-bin python3-gdal # Linux
|
|
34
|
+
pip install GDAL
|
|
35
|
+
```
|
|
36
|
+
> **Note:** GDAL is required to open `.hdf`, .`h5`, and `.hdf5` files. If it’s missing, viewtif will display: `RuntimeError: HDF support requires GDAL.`
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
```bash
|
|
40
|
+
# View a GeoTIFF
|
|
41
|
+
viewtif ECOSTRESS_LST.tif
|
|
42
|
+
|
|
43
|
+
# View an RGB composite
|
|
44
|
+
viewtif --rgbfiles \
|
|
45
|
+
HLS_B04.tif \
|
|
46
|
+
HLS_B03.tif \
|
|
47
|
+
HLS_B02.tif
|
|
48
|
+
|
|
49
|
+
# View with shapefile overlay
|
|
50
|
+
viewtif ECOSTRESS_LST.tif \
|
|
51
|
+
--shapefile Zip_Codes.shp
|
|
52
|
+
```
|
|
53
|
+
### Update in v1.0.6: HDF/HDF5 support
|
|
54
|
+
`viewtif` can open `.hdf`, `.h5`, and `.hdf5` files that contain multiple subdatasets. When opened, it lists available subdatasets and lets you view one by index. You can also specify a band to display (default is the first band) or change bands interactively with '[' and ']'.
|
|
55
|
+
```bash
|
|
56
|
+
# List subdatasets
|
|
57
|
+
viewtif AG100.v003.33.-107.0001.h5
|
|
58
|
+
|
|
59
|
+
# View a specific subdataset
|
|
60
|
+
viewtif AG100.v003.33.-107.0001.h5 --subset 1
|
|
61
|
+
|
|
62
|
+
# View a specific subdataset and band
|
|
63
|
+
viewtif AG100.v003.33.-107.0001.h5 --subset 1 --band 3
|
|
64
|
+
```
|
|
65
|
+
> **Note:** Some datasets (perhaps the majority of .hdf files) lack CRS information encoded, so shapefile overlays may not work. In that case, viewtif will display:
|
|
66
|
+
`[WARN] raster lacks CRS/transform; cannot place overlays.`
|
|
67
|
+
|
|
68
|
+
### Update in v1.0.7: File Geodatabase (.gdb) support
|
|
69
|
+
`viewtif` can now open raster datasets stored inside Esri File Geodatabases (`.gdb`), using the GDAL `OpenFileGDB` driver.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Example
|
|
73
|
+
viewtif "OpenFileGDB:/path/to/geodatabase.gdb:RasterName"
|
|
74
|
+
```
|
|
75
|
+
> **Note:** Requires GDAL 3.7 or later with the OpenFileGDB driver enabled. The .gdb path and raster name must be separated by a colon (:).
|
|
76
|
+
|
|
77
|
+
### Update in v1.0.7: Large raster safeguard
|
|
78
|
+
As of v1.0.7, `viewtif` automatically checks the raster size before loading.
|
|
79
|
+
If the dataset is very large (e.g., >20 million pixels), it will pause and warn that loading may freeze your system.
|
|
80
|
+
You can proceed manually or rerun with the `--scale` option for a smaller, faster preview.
|
|
81
|
+
|
|
82
|
+
## Controls
|
|
83
|
+
| Key | Action |
|
|
84
|
+
| -------------------- | --------------------------------------- |
|
|
85
|
+
| `+` / `-` or mouse / trackpad | Zoom in / out |
|
|
86
|
+
| Arrow keys or `WASD` | Pan |
|
|
87
|
+
| `C` / `V` | Increase / decrease contrast |
|
|
88
|
+
| `G` / `H` | Increase / decrease gamma |
|
|
89
|
+
| `M` | Toggle colormap (`viridis` ↔ `magma`) |
|
|
90
|
+
| `[` / `]` | Previous / next band (single-band only) |
|
|
91
|
+
| `R` | Reset view |
|
|
92
|
+
|
|
93
|
+
## Features
|
|
94
|
+
- Command-line driven GeoTIFF viewer.
|
|
95
|
+
- Supports single-band, RGB composite, and HDF/HDF5 subdatasets.
|
|
96
|
+
- Optional shapefile overlay for geographic context.
|
|
97
|
+
- Adjustable contrast, gamma, and colormap.
|
|
98
|
+
- Fast preview using rasterio and PySide6.
|
|
99
|
+
|
|
100
|
+
## Example Data
|
|
101
|
+
- ECOSTRESS_LST.tif
|
|
102
|
+
- Zip_Codes.shp and associated files
|
|
103
|
+
- HLS_B04.tif, HLS_B03.tif, HLS_B02.tif (RGB sample)
|
|
104
|
+
- AG100.v003.33.-107.0001.h5 (HDF5 file)
|
|
105
|
+
|
|
106
|
+
## Credit & License
|
|
107
|
+
`viewtif` was inspired by the NASA JPL Thermal Viewer — Semi-Automated Georeferencer (GeoViewer v1.12) developed by Jake Longenecker (University of Miami Rosenstiel School of Marine, Atmospheric & Earth Science) while at the NASA Jet Propulsion Laboratory, California Institute of Technology, with inspiration from JPL’s ECOSTRESS geolocation batch workflow by Andrew Alamillo. The original GeoViewer was released under the MIT License (2025) and may be freely adapted with citation.
|
|
108
|
+
|
|
109
|
+
## Citation
|
|
110
|
+
Longenecker, Jake; Lee, Christine; Hulley, Glynn; Cawse-Nicholson, Kerry; Purkis, Sam; Gleason, Art; Otis, Dan; Galdamez, Ileana; Meiseles, Jacquelyn. GeoViewer v1.12: NASA JPL Thermal Viewer—Semi-Automated Georeferencer User Guide & Reference Manual. Jet Propulsion Laboratory, California Institute of Technology, 2025. PDF.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
This project is released under the MIT License.
|
|
114
|
+
|
|
115
|
+
## Contributors
|
|
116
|
+
- [@HarshShinde0](https://github.com/HarshShinde0) — added mouse-wheel and trackpad zoom support
|
|
117
|
+
- [@p-vdp](https://github.com/p-vdp) — added File Geodatabase (.gdb) raster support
|
|
Binary file
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "viewtif"
|
|
7
|
-
version = "0.1.
|
|
8
|
-
description = "
|
|
7
|
+
version = "0.1.7"
|
|
8
|
+
description = "Lightweight GeoTIFF, HDF/HDF5, and Esri File Geodatabase (.gdb) viewer with shapefile overlay and large-raster safeguard."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
11
|
license = { text = "MIT" }
|
|
@@ -52,10 +52,38 @@ try:
|
|
|
52
52
|
except Exception:
|
|
53
53
|
HAVE_GEO = False
|
|
54
54
|
|
|
55
|
+
def warn_if_large(tif_path, scale=1):
|
|
56
|
+
"""Warn and confirm before loading very large rasters (GeoTIFF, GDB, or HDF)."""
|
|
57
|
+
from osgeo import gdal
|
|
58
|
+
import os
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
gdal.UseExceptions()
|
|
62
|
+
info = gdal.Info(tif_path, format="json")
|
|
63
|
+
width, height = info.get("size", [0, 0])
|
|
64
|
+
total_pixels = (width * height) / (scale ** 2) # account for downsampling
|
|
65
|
+
size_mb = None
|
|
66
|
+
if os.path.exists(tif_path):
|
|
67
|
+
size_mb = os.path.getsize(tif_path) / (1024 ** 2)
|
|
68
|
+
|
|
69
|
+
# Only warn if the *effective* pixels remain large
|
|
70
|
+
if total_pixels > 20_000_000 and scale <= 5:
|
|
71
|
+
print(
|
|
72
|
+
f"[WARN] Large raster detected ({width}×{height}, ~{total_pixels/1e6:.1f}M effective pixels"
|
|
73
|
+
+ (f", ~{size_mb:.1f} MB" if size_mb else "")
|
|
74
|
+
+ "). Loading may freeze. Consider rerunning with --scale (e.g. --scale 10)."
|
|
75
|
+
)
|
|
76
|
+
ans = input("Proceed anyway? [y/N]: ").strip().lower()
|
|
77
|
+
if ans not in ("y", "yes"):
|
|
78
|
+
print("Cancelled.")
|
|
79
|
+
sys.exit(0)
|
|
80
|
+
except Exception as e:
|
|
81
|
+
print(f"[WARN] Could not pre-check raster size: {e}")
|
|
55
82
|
|
|
56
83
|
# -------------------------- QGraphicsView tweaks -------------------------- #
|
|
57
84
|
class RasterView(QGraphicsView):
|
|
58
85
|
def __init__(self, *args, **kwargs):
|
|
86
|
+
import numpy as np
|
|
59
87
|
super().__init__(*args, **kwargs)
|
|
60
88
|
self.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform, False)
|
|
61
89
|
self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)
|
|
@@ -101,6 +129,7 @@ class TiffViewer(QMainWindow):
|
|
|
101
129
|
shapefiles: list[str] | None = None,
|
|
102
130
|
shp_color: str = "white",
|
|
103
131
|
shp_width: float = 2,
|
|
132
|
+
subset: int | None = None,
|
|
104
133
|
):
|
|
105
134
|
super().__init__()
|
|
106
135
|
|
|
@@ -141,38 +170,123 @@ class TiffViewer(QMainWindow):
|
|
|
141
170
|
self.tif_path = self.tif_path or (os.path.commonprefix([red, green, blue]) or red)
|
|
142
171
|
|
|
143
172
|
elif tif_path:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
173
|
+
# --- Universal size check before loading ---
|
|
174
|
+
warn_if_large(tif_path, scale=self._scale_arg)
|
|
175
|
+
# --------------------- Detect HDF/HDF5 --------------------- #
|
|
176
|
+
if tif_path.lower().endswith((".hdf", ".h5", ".hdf5")):
|
|
177
|
+
try:
|
|
178
|
+
from osgeo import gdal
|
|
179
|
+
gdal.UseExceptions()
|
|
180
|
+
|
|
181
|
+
ds = gdal.Open(tif_path)
|
|
182
|
+
subs = ds.GetSubDatasets()
|
|
183
|
+
|
|
184
|
+
if not subs:
|
|
185
|
+
raise ValueError("No subdatasets found in HDF/HDF5 file.")
|
|
186
|
+
|
|
187
|
+
print(f"Found {len(subs)} subdatasets in {os.path.basename(tif_path)}:")
|
|
188
|
+
for i, (_, desc) in enumerate(subs):
|
|
189
|
+
print(f"[{i}] {desc}")
|
|
190
|
+
|
|
191
|
+
# Only list subsets if --subset not given
|
|
192
|
+
if subset is None:
|
|
193
|
+
print("\nUse --subset N to open a specific subdataset.")
|
|
194
|
+
sys.exit(0)
|
|
195
|
+
|
|
196
|
+
# Validate subset index
|
|
197
|
+
if subset < 0 or subset >= len(subs):
|
|
198
|
+
raise ValueError(f"Invalid subset index {subset}. Valid range: 0–{len(subs)-1}")
|
|
199
|
+
|
|
200
|
+
sub_name, desc = subs[subset]
|
|
201
|
+
print(f"\nOpening subdataset [{subset}]: {desc}")
|
|
202
|
+
sub_ds = gdal.Open(sub_name)
|
|
203
|
+
|
|
204
|
+
# --- Read once ---
|
|
205
|
+
arr = sub_ds.ReadAsArray().astype(np.float32)
|
|
206
|
+
#print(f"Raw array shape from GDAL: {arr.shape} (ndim={arr.ndim})")
|
|
207
|
+
|
|
208
|
+
# --- Normalize shape ---
|
|
209
|
+
arr = np.squeeze(arr)
|
|
210
|
+
if arr.ndim == 3:
|
|
211
|
+
# Convert from (bands, rows, cols) → (rows, cols, bands)
|
|
212
|
+
arr = np.transpose(arr, (1, 2, 0))
|
|
213
|
+
#print(f"Transposed to {arr.shape} (rows, cols, bands)")
|
|
214
|
+
elif arr.ndim == 2:
|
|
215
|
+
print("Single-band dataset.")
|
|
216
|
+
else:
|
|
217
|
+
raise ValueError(f"Unexpected array shape {arr.shape}")
|
|
218
|
+
|
|
219
|
+
# --- Downsample large arrays for responsiveness ---
|
|
220
|
+
h, w = arr.shape[:2]
|
|
221
|
+
if h * w > 4_000_000:
|
|
222
|
+
step = max(2, int((h * w / 4_000_000) ** 0.5))
|
|
223
|
+
arr = arr[::step, ::step] if arr.ndim == 2 else arr[::step, ::step, :]
|
|
224
|
+
print(f"⚠️ Large dataset preview: downsampled by {step}x")
|
|
225
|
+
|
|
226
|
+
# --- Final assignments ---
|
|
154
227
|
self.data = arr
|
|
155
|
-
self.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
228
|
+
self._transform = None
|
|
229
|
+
self._crs = None
|
|
230
|
+
self.band_count = arr.shape[2] if arr.ndim == 3 else 1
|
|
231
|
+
self.band_index = 0
|
|
232
|
+
self.vmin, self.vmax = np.nanmin(arr), np.nanmax(arr)
|
|
233
|
+
|
|
234
|
+
if self.band_count > 1:
|
|
235
|
+
print(f"This subdataset has {self.band_count} bands — switch with [ and ] keys.")
|
|
236
|
+
else:
|
|
237
|
+
print("This subdataset has 1 band.")
|
|
238
|
+
|
|
239
|
+
# --- If user specified --band, start there ---
|
|
240
|
+
if self.band and self.band <= self.band_count:
|
|
241
|
+
self.band_index = self.band - 1
|
|
242
|
+
print(f"Opening band {self.band}/{self.band_count}")
|
|
243
|
+
else:
|
|
244
|
+
self.band_index = 0
|
|
245
|
+
|
|
246
|
+
except ImportError:
|
|
247
|
+
raise RuntimeError(
|
|
248
|
+
"HDF support requires GDAL.\n"
|
|
249
|
+
"Install it first (e.g., brew install gdal && pip install GDAL)"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# --------------------- Regular GeoTIFF --------------------- #
|
|
253
|
+
else:
|
|
254
|
+
if os.path.dirname(tif_path).endswith(".gdb"):
|
|
255
|
+
tif_path = f"OpenFileGDB:{os.path.dirname(tif_path)}:{os.path.basename(tif_path)}"
|
|
256
|
+
|
|
257
|
+
with rasterio.open(tif_path) as src:
|
|
258
|
+
self._transform = src.transform
|
|
259
|
+
self._crs = src.crs
|
|
260
|
+
if rgb is not None:
|
|
261
|
+
bands = [src.read(b, out_shape=(src.height // self._scale_arg, src.width // self._scale_arg))
|
|
262
|
+
for b in rgb]
|
|
263
|
+
arr = np.stack(bands, axis=-1).astype(np.float32)
|
|
264
|
+
nd = src.nodata
|
|
265
|
+
if nd is not None:
|
|
266
|
+
arr[arr == nd] = np.nan
|
|
267
|
+
self.data = arr
|
|
268
|
+
self.band_count = 3
|
|
269
|
+
else:
|
|
270
|
+
arr = src.read(
|
|
271
|
+
self.band,
|
|
272
|
+
out_shape=(src.height // self._scale_arg, src.width // self._scale_arg)
|
|
273
|
+
).astype(np.float32)
|
|
274
|
+
nd = src.nodata
|
|
275
|
+
if nd is not None:
|
|
276
|
+
arr[arr == nd] = np.nan
|
|
277
|
+
self.data = arr
|
|
278
|
+
self.band_count = src.count
|
|
279
|
+
|
|
280
|
+
# single-band display range (fast stats or fallback)
|
|
281
|
+
try:
|
|
282
|
+
stats = src.stats(self.band)
|
|
283
|
+
if stats and stats.min is not None and stats.max is not None:
|
|
284
|
+
self.vmin, self.vmax = stats.min, stats.max
|
|
285
|
+
else:
|
|
286
|
+
raise ValueError("No stats in file")
|
|
287
|
+
except Exception:
|
|
288
|
+
self.vmin, self.vmax = np.nanmin(arr), np.nanmax(arr)
|
|
289
|
+
|
|
176
290
|
else:
|
|
177
291
|
raise ValueError("Provide a TIFF path or --rgbfiles.")
|
|
178
292
|
|
|
@@ -339,6 +453,10 @@ class TiffViewer(QMainWindow):
|
|
|
339
453
|
self.setWindowTitle(f"RGB ({', '.join(names)})")
|
|
340
454
|
elif self.rgb_mode and self.rgb:
|
|
341
455
|
self.setWindowTitle(f"RGB {self.rgb} — {os.path.basename(self.tif_path)}")
|
|
456
|
+
elif hasattr(self, "band_index"):
|
|
457
|
+
self.setWindowTitle(
|
|
458
|
+
f"Band {self.band_index + 1}/{self.band_count} — {os.path.basename(self.tif_path)}"
|
|
459
|
+
)
|
|
342
460
|
else:
|
|
343
461
|
self.setWindowTitle(f"Band {self.band}/{self.band_count} — {os.path.basename(self.tif_path)}")
|
|
344
462
|
|
|
@@ -371,10 +489,44 @@ class TiffViewer(QMainWindow):
|
|
|
371
489
|
return rgb
|
|
372
490
|
|
|
373
491
|
def update_pixmap(self):
|
|
374
|
-
|
|
492
|
+
# --- Select display data ---
|
|
493
|
+
if hasattr(self, "band_index"):
|
|
494
|
+
# HDF or scientific multi-band
|
|
495
|
+
if self.data.ndim == 3:
|
|
496
|
+
a = self.data[:, :, self.band_index]
|
|
497
|
+
else:
|
|
498
|
+
a = self.data
|
|
499
|
+
rgb = None
|
|
500
|
+
else:
|
|
501
|
+
# Regular GeoTIFF (could be RGB or single-band)
|
|
502
|
+
if self.rgb_mode: # user explicitly passed --rgb or --rgbtiles
|
|
503
|
+
rgb = self.data
|
|
504
|
+
a = None
|
|
505
|
+
else:
|
|
506
|
+
a = self.data
|
|
507
|
+
rgb = None
|
|
508
|
+
# ----------------------------
|
|
509
|
+
|
|
510
|
+
# --- Render image ---
|
|
511
|
+
if rgb is None:
|
|
512
|
+
# Grayscale rendering for single-band (scientific) data
|
|
513
|
+
finite = np.isfinite(a)
|
|
514
|
+
rng = max(np.nanmax(a) - np.nanmin(a), 1e-12)
|
|
515
|
+
norm = np.zeros_like(a, dtype=np.float32)
|
|
516
|
+
if np.any(finite):
|
|
517
|
+
norm[finite] = (a[finite] - np.nanmin(a)) / rng
|
|
518
|
+
norm = np.clip(norm, 0, 1)
|
|
519
|
+
norm = np.power(norm * self.contrast, self.gamma)
|
|
520
|
+
cmap = getattr(cm, self.cmap_name, cm.viridis)
|
|
521
|
+
rgb = (cmap(norm)[..., :3] * 255).astype(np.uint8)
|
|
522
|
+
else:
|
|
523
|
+
# True RGB mode (unchanged)
|
|
524
|
+
rgb = self._render_rgb()
|
|
525
|
+
# ----------------------
|
|
526
|
+
|
|
375
527
|
h, w, _ = rgb.shape
|
|
376
528
|
self._last_rgb = rgb
|
|
377
|
-
qimg = QImage(
|
|
529
|
+
qimg = QImage(rgb.data, w, h, 3 * w, QImage.Format.Format_RGB888)
|
|
378
530
|
pix = QPixmap.fromImage(qimg)
|
|
379
531
|
if self.pixmap_item is None:
|
|
380
532
|
self.pixmap_item = QGraphicsPixmapItem(pix)
|
|
@@ -387,7 +539,13 @@ class TiffViewer(QMainWindow):
|
|
|
387
539
|
def load_band(self, band_num: int):
|
|
388
540
|
if self.rgb_mode:
|
|
389
541
|
return
|
|
390
|
-
|
|
542
|
+
|
|
543
|
+
tif_path = self.tif_path
|
|
544
|
+
|
|
545
|
+
if os.path.dirname(self.tif_path).endswith(".gdb"):
|
|
546
|
+
tif_path = f"OpenFileGDB:{os.path.dirname(self.tif_path)}:{os.path.basename(self.tif_path)}"
|
|
547
|
+
|
|
548
|
+
with rasterio.open(tif_path) as src:
|
|
391
549
|
self.band = band_num
|
|
392
550
|
arr = src.read(self.band).astype(np.float32)
|
|
393
551
|
nd = src.nodata
|
|
@@ -433,13 +591,24 @@ class TiffViewer(QMainWindow):
|
|
|
433
591
|
self.cmap_name, self.alt_cmap_name = self.alt_cmap_name, self.cmap_name
|
|
434
592
|
self.update_pixmap()
|
|
435
593
|
|
|
436
|
-
# Band switch
|
|
437
|
-
elif
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
self.
|
|
594
|
+
# Band switch
|
|
595
|
+
elif k == Qt.Key.Key_BracketRight:
|
|
596
|
+
if hasattr(self, "band_index"): # HDF/NetCDF mode
|
|
597
|
+
self.band_index = (self.band_index + 1) % self.band_count
|
|
598
|
+
self.update_pixmap()
|
|
599
|
+
self.update_title()
|
|
600
|
+
elif not self.rgb_mode: # GeoTIFF single-band mode
|
|
601
|
+
new_band = self.band + 1 if self.band < self.band_count else 1
|
|
602
|
+
self.load_band(new_band)
|
|
603
|
+
|
|
604
|
+
elif k == Qt.Key.Key_BracketLeft:
|
|
605
|
+
if hasattr(self, "band_index"): # HDF/NetCDF mode
|
|
606
|
+
self.band_index = (self.band_index - 1) % self.band_count
|
|
607
|
+
self.update_pixmap()
|
|
608
|
+
self.update_title()
|
|
609
|
+
elif not self.rgb_mode: # GeoTIFF single-band mode
|
|
610
|
+
new_band = self.band - 1 if self.band > 1 else self.band_count
|
|
611
|
+
self.load_band(new_band)
|
|
443
612
|
|
|
444
613
|
elif k == Qt.Key.Key_R:
|
|
445
614
|
self.contrast = 1.0
|
|
@@ -488,6 +657,7 @@ def run_viewer(
|
|
|
488
657
|
shapefile=None,
|
|
489
658
|
shp_color=None,
|
|
490
659
|
shp_width=None,
|
|
660
|
+
subset=None,
|
|
491
661
|
):
|
|
492
662
|
"""Launch the TiffViewer app"""
|
|
493
663
|
app = QApplication(sys.argv)
|
|
@@ -500,6 +670,7 @@ def run_viewer(
|
|
|
500
670
|
shapefiles=shapefile,
|
|
501
671
|
shp_color=shp_color,
|
|
502
672
|
shp_width=shp_width,
|
|
673
|
+
subset=subset,
|
|
503
674
|
)
|
|
504
675
|
win.show()
|
|
505
676
|
sys.exit(app.exec())
|
|
@@ -507,6 +678,7 @@ def run_viewer(
|
|
|
507
678
|
import click
|
|
508
679
|
|
|
509
680
|
@click.command()
|
|
681
|
+
@click.version_option("1.0.6", prog_name="viewtif")
|
|
510
682
|
@click.argument("tif_path", required=False)
|
|
511
683
|
@click.option("--band", default=1, show_default=True, type=int, help="Band number to display")
|
|
512
684
|
@click.option("--scale", default=1.0, show_default=True, type=float, help="Scale factor for display")
|
|
@@ -515,9 +687,9 @@ import click
|
|
|
515
687
|
@click.option("--shapefile", multiple=True, type=str, help="One or more shapefiles to overlay")
|
|
516
688
|
@click.option("--shp-color", default="white", show_default=True, help="Overlay color (name or #RRGGBB).")
|
|
517
689
|
@click.option("--shp-width", default=1.0, show_default=True, type=float, help="Overlay line width (screen pixels).")
|
|
518
|
-
|
|
690
|
+
@click.option("--subset", default=None, type=int, help="Open specific subdataset index in .hdf/.h5 file")
|
|
691
|
+
def main(tif_path, band, scale, rgb, rgbfiles, shapefile, shp_color, shp_width, subset):
|
|
519
692
|
"""Lightweight GeoTIFF viewer."""
|
|
520
|
-
|
|
521
693
|
# --- Warn early if shapefile requested but geopandas missing ---
|
|
522
694
|
if shapefile and not HAVE_GEO:
|
|
523
695
|
print(
|
|
@@ -535,9 +707,9 @@ def main(tif_path, band, scale, rgb, rgbfiles, shapefile, shp_color, shp_width):
|
|
|
535
707
|
shapefile=shapefile,
|
|
536
708
|
shp_color=shp_color,
|
|
537
709
|
shp_width=shp_width,
|
|
710
|
+
subset=subset,
|
|
538
711
|
)
|
|
539
712
|
|
|
540
|
-
|
|
541
713
|
if __name__ == "__main__":
|
|
542
714
|
main()
|
|
543
715
|
|
viewtif-0.1.5/.gitignore
DELETED
viewtif-0.1.5/PKG-INFO
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: viewtif
|
|
3
|
-
Version: 0.1.5
|
|
4
|
-
Summary: Simple GeoTIFF viewer with optional shapefile overlay.
|
|
5
|
-
Project-URL: Homepage, https://github.com/nkeikon/tifviewer
|
|
6
|
-
Project-URL: Source, https://github.com/nkeikon/tifviewer
|
|
7
|
-
Project-URL: Issues, https://github.com/nkeikon/tifviewer/issues
|
|
8
|
-
Author: Keiko Nomura
|
|
9
|
-
License: MIT
|
|
10
|
-
Requires-Python: >=3.9
|
|
11
|
-
Requires-Dist: click>=8.1
|
|
12
|
-
Requires-Dist: matplotlib>=3.7
|
|
13
|
-
Requires-Dist: numpy>=1.23
|
|
14
|
-
Requires-Dist: pyside6>=6.5
|
|
15
|
-
Requires-Dist: rasterio>=1.3
|
|
16
|
-
Provides-Extra: geo
|
|
17
|
-
Requires-Dist: geopandas>=0.13; extra == 'geo'
|
|
18
|
-
Requires-Dist: shapely>=2.0; extra == 'geo'
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
|
|
21
|
-
# viewtif
|
|
22
|
-
|
|
23
|
-
A lightweight GeoTIFF viewer for quick visualization directly from the command line.
|
|
24
|
-
|
|
25
|
-
You can visualize single-band GeoTIFFs, RGB composites, and shapefile overlays in a simple Qt-based window.
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Installation
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pip install viewtif
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
If you want to enable shapefile overlays, install with optional dependencies:
|
|
36
|
-
```bash
|
|
37
|
-
pip install "viewtif[geo]"
|
|
38
|
-
```
|
|
39
|
-
Note for macOS(zsh) users:
|
|
40
|
-
Make sure to include the quotes, or zsh will interpret it as a pattern.
|
|
41
|
-
|
|
42
|
-
## Quick Start
|
|
43
|
-
```bash
|
|
44
|
-
# View a GeoTIFF
|
|
45
|
-
viewtif examples/sample_data/ECOSTRESS_LST.tif
|
|
46
|
-
|
|
47
|
-
# View with shapefile overlay
|
|
48
|
-
viewtif examples/sample_data/ECOSTRESS_LST.tif \
|
|
49
|
-
--shapefile examples/sample_data/Zip_Codes.shp
|
|
50
|
-
|
|
51
|
-
# View an RGB composite
|
|
52
|
-
viewtif --rgbfiles \
|
|
53
|
-
examples/sample_data/HLS_B04.tif \
|
|
54
|
-
examples/sample_data/HLS_B03.tif \
|
|
55
|
-
examples/sample_data/HLS_B02.tif
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Controls
|
|
60
|
-
| Key | Action |
|
|
61
|
-
| -------------------- | --------------------------------------- |
|
|
62
|
-
| `+` / `-` | Zoom in / out |
|
|
63
|
-
| Arrow keys or `WASD` | Pan |
|
|
64
|
-
| `C` / `V` | Increase / decrease contrast |
|
|
65
|
-
| `G` / `H` | Increase / decrease gamma |
|
|
66
|
-
| `M` | Toggle colormap (`viridis` ↔ `magma`) |
|
|
67
|
-
| `[` / `]` | Previous / next band (single-band only) |
|
|
68
|
-
| `R` | Reset view |
|
|
69
|
-
|
|
70
|
-
## Features
|
|
71
|
-
- Command-line driven GeoTIFF viewer
|
|
72
|
-
- Supports single-band or RGB composite display.
|
|
73
|
-
- Optional shapefile overlay for geographic context.
|
|
74
|
-
- Adjustable contrast, gamma, and colormap.
|
|
75
|
-
- Fast preview using rasterio and PySide6.
|
|
76
|
-
|
|
77
|
-
## Example Data
|
|
78
|
-
- ECOSTRESS_LST.tif
|
|
79
|
-
- Zip_Codes.shp and associated files
|
|
80
|
-
- HLS_B04.tif, HLS_B03.tif, HLS_B02.tif (RGB sample)
|
|
81
|
-
|
|
82
|
-
## Credit & License
|
|
83
|
-
`viewtif` was inspired by the NASA JPL Thermal Viewer — Semi-Automated Georeferencer (GeoViewer v1.12) developed by Jake Longenecker (University of Miami Rosenstiel School of Marine, Atmospheric & Earth Science) while at the NASA Jet Propulsion Laboratory, California Institute of Technology, with inspiration from JPL’s ECOSTRESS geolocation batch workflow by Andrew Alamillo. The original GeoViewer was released under the MIT License (2025) and may be freely adapted with citation.
|
|
84
|
-
|
|
85
|
-
# Citation
|
|
86
|
-
Longenecker, Jake; Lee, Christine; Hulley, Glynn; Cawse-Nicholson, Kerry; Purkis, Sam; Gleason, Art; Otis, Dan; Galdamez,Ileana; Meiseles, Jacquelyn. GeoViewer v1.12: NASA JPL Thermal Viewer—Semi-Automated Georeferencer User Guide & Reference Manual. Jet Propulsion Laboratory, California Institute of Technology, 2025. PDF.
|
|
87
|
-
|
|
88
|
-
# License
|
|
89
|
-
This project is released under the MIT License.
|
|
90
|
-
|
|
91
|
-
## Contributors
|
|
92
|
-
- [@HarshShinde0](https://github.com/HarshShinde0) — added mouse-wheel and trackpad zoom support
|
|
93
|
-
|
viewtif-0.1.5/README.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# viewtif
|
|
2
|
-
|
|
3
|
-
A lightweight GeoTIFF viewer for quick visualization directly from the command line.
|
|
4
|
-
|
|
5
|
-
You can visualize single-band GeoTIFFs, RGB composites, and shapefile overlays in a simple Qt-based window.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
pip install viewtif
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
If you want to enable shapefile overlays, install with optional dependencies:
|
|
16
|
-
```bash
|
|
17
|
-
pip install "viewtif[geo]"
|
|
18
|
-
```
|
|
19
|
-
Note for macOS(zsh) users:
|
|
20
|
-
Make sure to include the quotes, or zsh will interpret it as a pattern.
|
|
21
|
-
|
|
22
|
-
## Quick Start
|
|
23
|
-
```bash
|
|
24
|
-
# View a GeoTIFF
|
|
25
|
-
viewtif examples/sample_data/ECOSTRESS_LST.tif
|
|
26
|
-
|
|
27
|
-
# View with shapefile overlay
|
|
28
|
-
viewtif examples/sample_data/ECOSTRESS_LST.tif \
|
|
29
|
-
--shapefile examples/sample_data/Zip_Codes.shp
|
|
30
|
-
|
|
31
|
-
# View an RGB composite
|
|
32
|
-
viewtif --rgbfiles \
|
|
33
|
-
examples/sample_data/HLS_B04.tif \
|
|
34
|
-
examples/sample_data/HLS_B03.tif \
|
|
35
|
-
examples/sample_data/HLS_B02.tif
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Controls
|
|
40
|
-
| Key | Action |
|
|
41
|
-
| -------------------- | --------------------------------------- |
|
|
42
|
-
| `+` / `-` | Zoom in / out |
|
|
43
|
-
| Arrow keys or `WASD` | Pan |
|
|
44
|
-
| `C` / `V` | Increase / decrease contrast |
|
|
45
|
-
| `G` / `H` | Increase / decrease gamma |
|
|
46
|
-
| `M` | Toggle colormap (`viridis` ↔ `magma`) |
|
|
47
|
-
| `[` / `]` | Previous / next band (single-band only) |
|
|
48
|
-
| `R` | Reset view |
|
|
49
|
-
|
|
50
|
-
## Features
|
|
51
|
-
- Command-line driven GeoTIFF viewer
|
|
52
|
-
- Supports single-band or RGB composite display.
|
|
53
|
-
- Optional shapefile overlay for geographic context.
|
|
54
|
-
- Adjustable contrast, gamma, and colormap.
|
|
55
|
-
- Fast preview using rasterio and PySide6.
|
|
56
|
-
|
|
57
|
-
## Example Data
|
|
58
|
-
- ECOSTRESS_LST.tif
|
|
59
|
-
- Zip_Codes.shp and associated files
|
|
60
|
-
- HLS_B04.tif, HLS_B03.tif, HLS_B02.tif (RGB sample)
|
|
61
|
-
|
|
62
|
-
## Credit & License
|
|
63
|
-
`viewtif` was inspired by the NASA JPL Thermal Viewer — Semi-Automated Georeferencer (GeoViewer v1.12) developed by Jake Longenecker (University of Miami Rosenstiel School of Marine, Atmospheric & Earth Science) while at the NASA Jet Propulsion Laboratory, California Institute of Technology, with inspiration from JPL’s ECOSTRESS geolocation batch workflow by Andrew Alamillo. The original GeoViewer was released under the MIT License (2025) and may be freely adapted with citation.
|
|
64
|
-
|
|
65
|
-
# Citation
|
|
66
|
-
Longenecker, Jake; Lee, Christine; Hulley, Glynn; Cawse-Nicholson, Kerry; Purkis, Sam; Gleason, Art; Otis, Dan; Galdamez,Ileana; Meiseles, Jacquelyn. GeoViewer v1.12: NASA JPL Thermal Viewer—Semi-Automated Georeferencer User Guide & Reference Manual. Jet Propulsion Laboratory, California Institute of Technology, 2025. PDF.
|
|
67
|
-
|
|
68
|
-
# License
|
|
69
|
-
This project is released under the MIT License.
|
|
70
|
-
|
|
71
|
-
## Contributors
|
|
72
|
-
- [@HarshShinde0](https://github.com/HarshShinde0) — added mouse-wheel and trackpad zoom support
|
|
73
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|