Skip to content

Commit 97c4e02

Browse files
authored
Minimal Python typing interface (#19)
1 parent eddea60 commit 97c4e02

File tree

8 files changed

+212
-9
lines changed

8 files changed

+212
-9
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from ._geo import GeoKeyDirectory as GeoKeyDirectory
2+
from ._ifd import ImageFileDirectory as ImageFileDirectory
3+
from ._tiff import TIFF as TIFF

python/python/async_tiff/_geo.pyi

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
class GeoKeyDirectory:
2+
@property
3+
def model_type(self) -> int | None: ...
4+
@property
5+
def raster_type(self) -> int | None: ...
6+
@property
7+
def citation(self) -> str | None: ...
8+
@property
9+
def geographic_type(self) -> int | None: ...
10+
@property
11+
def geog_citation(self) -> str | None: ...
12+
@property
13+
def geog_geodetic_datum(self) -> int | None: ...
14+
@property
15+
def geog_prime_meridian(self) -> int | None: ...
16+
@property
17+
def geog_linear_units(self) -> int | None: ...
18+
@property
19+
def geog_linear_unit_size(self) -> float | None: ...
20+
@property
21+
def geog_angular_units(self) -> int | None: ...
22+
@property
23+
def geog_angular_unit_size(self) -> float | None: ...
24+
@property
25+
def geog_ellipsoid(self) -> int | None: ...
26+
@property
27+
def geog_semi_major_axis(self) -> float | None: ...
28+
@property
29+
def geog_semi_minor_axis(self) -> float | None: ...
30+
@property
31+
def geog_inv_flattening(self) -> float | None: ...
32+
@property
33+
def geog_azimuth_units(self) -> int | None: ...
34+
@property
35+
def geog_prime_meridian_long(self) -> float | None: ...
36+
@property
37+
def projected_type(self) -> int | None: ...
38+
@property
39+
def proj_citation(self) -> str | None: ...
40+
@property
41+
def projection(self) -> int | None: ...
42+
@property
43+
def proj_coord_trans(self) -> int | None: ...
44+
@property
45+
def proj_linear_units(self) -> int | None: ...
46+
@property
47+
def proj_linear_unit_size(self) -> float | None: ...
48+
@property
49+
def proj_std_parallel1(self) -> float | None: ...
50+
@property
51+
def proj_std_parallel2(self) -> float | None: ...
52+
@property
53+
def proj_nat_origin_long(self) -> float | None: ...
54+
@property
55+
def proj_nat_origin_lat(self) -> float | None: ...
56+
@property
57+
def proj_false_easting(self) -> float | None: ...
58+
@property
59+
def proj_false_northing(self) -> float | None: ...
60+
@property
61+
def proj_false_origin_long(self) -> float | None: ...
62+
@property
63+
def proj_false_origin_lat(self) -> float | None: ...
64+
@property
65+
def proj_false_origin_easting(self) -> float | None: ...
66+
@property
67+
def proj_false_origin_northing(self) -> float | None: ...
68+
@property
69+
def proj_center_long(self) -> float | None: ...
70+
@property
71+
def proj_center_lat(self) -> float | None: ...
72+
@property
73+
def proj_center_easting(self) -> float | None: ...
74+
@property
75+
def proj_center_northing(self) -> float | None: ...
76+
@property
77+
def proj_scale_at_nat_origin(self) -> float | None: ...
78+
@property
79+
def proj_scale_at_center(self) -> float | None: ...
80+
@property
81+
def proj_azimuth_angle(self) -> float | None: ...
82+
@property
83+
def proj_straight_vert_pole_long(self) -> float | None: ...
84+
@property
85+
def vertical(self) -> int | None: ...
86+
@property
87+
def vertical_citation(self) -> str | None: ...
88+
@property
89+
def vertical_datum(self) -> int | None: ...
90+
@property
91+
def vertical_units(self) -> int | None: ...

python/python/async_tiff/_ifd.pyi

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from .enums import (
2+
CompressionMethod,
3+
PhotometricInterpretation,
4+
PlanarConfiguration,
5+
Predictor,
6+
ResolutionUnit,
7+
SampleFormat,
8+
)
9+
from ._geo import GeoKeyDirectory
10+
11+
class ImageFileDirectory:
12+
@property
13+
def new_subfile_type(self) -> int | None: ...
14+
@property
15+
def image_width(self) -> int:
16+
"""The number of columns in the image, i.e., the number of pixels per row."""
17+
18+
@property
19+
def image_height(self) -> int:
20+
"""The number of rows of pixels in the image."""
21+
22+
@property
23+
def bits_per_sample(self) -> list[int]: ...
24+
@property
25+
def compression(self) -> CompressionMethod: ...
26+
@property
27+
def photometric_interpretation(self) -> PhotometricInterpretation: ...
28+
@property
29+
def document_name(self) -> str | None: ...
30+
@property
31+
def image_description(self) -> str | None: ...
32+
@property
33+
def strip_offsets(self) -> list[int] | None: ...
34+
@property
35+
def orientation(self) -> int | None: ...
36+
@property
37+
def samples_per_pixel(self) -> int:
38+
"""
39+
The number of components per pixel.
40+
41+
SamplesPerPixel is usually 1 for bilevel, grayscale, and palette-color images.
42+
SamplesPerPixel is usually 3 for RGB images. If this value is higher,
43+
ExtraSamples should give an indication of the meaning of the additional
44+
channels.
45+
"""
46+
47+
@property
48+
def rows_per_strip(self) -> int | None: ...
49+
@property
50+
def strip_byte_counts(self) -> int | None: ...
51+
@property
52+
def min_sample_value(self) -> int | None: ...
53+
@property
54+
def max_sample_value(self) -> int | None: ...
55+
@property
56+
def x_resolution(self) -> float | None:
57+
"""The number of pixels per ResolutionUnit in the ImageWidth direction."""
58+
59+
@property
60+
def y_resolution(self) -> float | None:
61+
"""The number of pixels per ResolutionUnit in the ImageLength direction."""
62+
63+
@property
64+
def planar_configuration(self) -> PlanarConfiguration: ...
65+
@property
66+
def resolution_unit(self) -> ResolutionUnit | None: ...
67+
@property
68+
def software(self) -> str | None: ...
69+
@property
70+
def date_time(self) -> str | None: ...
71+
@property
72+
def artist(self) -> str | None: ...
73+
@property
74+
def host_computer(self) -> str | None: ...
75+
@property
76+
def predictor(self) -> Predictor | None: ...
77+
@property
78+
def tile_width(self) -> int: ...
79+
@property
80+
def tile_height(self) -> int: ...
81+
@property
82+
def tile_offsets(self) -> list[int]: ...
83+
@property
84+
def tile_byte_counts(self) -> list[int]: ...
85+
@property
86+
def extra_samples(self) -> bytes | None: ...
87+
@property
88+
def sample_format(self) -> list[SampleFormat]: ...
89+
@property
90+
def jpeg_tables(self) -> bytes | None: ...
91+
@property
92+
def copyright(self) -> str | None: ...
93+
@property
94+
def geo_key_directory(self) -> GeoKeyDirectory | None: ...
95+
@property
96+
def model_pixel_scale(self) -> list[float] | None: ...
97+
@property
98+
def model_tiepoint(self) -> list[float] | None: ...

python/python/async_tiff/_tiff.pyi

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from typing import Any
2+
3+
from ._ifd import ImageFileDirectory
4+
5+
class TIFF:
6+
@classmethod
7+
async def open(
8+
cls, path: str, *, store: Any, prefetch: int | None = 16384
9+
) -> TIFF: ...
10+
@property
11+
def ifds(self) -> list[ImageFileDirectory]: ...

python/src/tiff.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ impl PyTIFF {
3737
Ok(cog_reader)
3838
}
3939

40+
#[getter]
4041
fn ifds(&self) -> Vec<PyImageFileDirectory> {
4142
let ifds = self.0.ifds();
4243
ifds.as_ref().iter().map(|ifd| ifd.clone().into()).collect()

python/tests/test_cog.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import async_tiff
2+
from time import time
23
from async_tiff import TIFF
34
from async_tiff.store import S3Store
45

56
store = S3Store("sentinel-cogs", region="us-west-2", skip_signature=True)
67
path = "sentinel-s2-l2a-cogs/12/S/UF/2022/6/S2B_12SUF_20220609_0_L2A/B04.tif"
78

8-
# 2 min, 15s
99
tiff = await TIFF.open(path, store=store, prefetch=32768)
10-
ifds = tiff.ifds()
10+
11+
start = time()
12+
tiff = await TIFF.open(path, store=store, prefetch=32768)
13+
end = time()
14+
end - start
15+
16+
ifds = tiff.ifds
1117
ifd = ifds[0]
1218
ifd.compression
1319
ifd.tile_height

src/cog.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,8 @@ mod test {
6666
let cog_reader = COGReader::try_open(Box::new(reader.clone())).await.unwrap();
6767

6868
let ifd = &cog_reader.ifds.as_ref()[1];
69-
// dbg!(ifd.geotransform());
70-
dbg!(ifd);
7169
let tile = ifd.get_tile(0, 0, Box::new(reader)).await.unwrap();
7270
std::fs::write("img.buf", tile).unwrap();
73-
// dbg!(tile.len());
7471
}
7572

7673
#[ignore = "local file"]

src/ifd.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ impl ImageFileDirectories {
4747
next_ifd_offset = ifd.next_ifd_offset();
4848
ifds.push(ifd);
4949
}
50-
dbg!(&ifds[0].compression);
5150

5251
Ok(Self { ifds })
5352
}
@@ -771,7 +770,6 @@ impl ImageFileDirectory {
771770
async fn read_tag(cursor: &mut AsyncCursor) -> Result<(Tag, Value)> {
772771
let code = cursor.read_u16().await?;
773772
let tag_name = Tag::from_u16_exhaustive(code);
774-
// dbg!(&tag_name);
775773

776774
let current_cursor_position = cursor.position();
777775

@@ -823,8 +821,6 @@ async fn read_tag_value(
823821
// 2a: the value is 5-8 bytes and we're in BigTiff mode.
824822
// We don't support bigtiff yet
825823

826-
// dbg!(value_byte_length);
827-
// dbg!(tag_type);
828824
// NOTE: we should only be reading value_byte_length when it's 4 bytes or fewer. Right now
829825
// we're reading even if it's 8 bytes, but then only using the first 4 bytes of this
830826
// buffer.

0 commit comments

Comments
 (0)