Skip to content

Commit 7007724

Browse files
authored
Cleanup (#9)
* Move geo-specific stuff to geo mod * Rename ObjectStoreCursor to AsyncCursor * Rename to async-tiff
1 parent 98d496f commit 7007724

File tree

12 files changed

+143
-144
lines changed

12 files changed

+143
-144
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "aiocogeo"
2+
name = "async-tiff"
33
version = "0.1.0"
44
edition = "2021"
55

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
# aiocogeo-rs
2-
Exploratory rust version of aiocogeo
1+
# async-tiff
32

3+
An async [TIFF](https://en.wikipedia.org/wiki/TIFF) reader.
4+
5+
The existing [`tiff` crate](https://crates.io/crates/tiff) is great, but only supports synchronous reading of TIFF files. Furthermore, due to low maintenance bandwidth it is not designed for extensibility (see [#250](https://github.com/image-rs/image-tiff/issues/250)).
6+
7+
This crate is designed to be a minimal, low-level interface to read tiled TIFF files in an async way.
8+
9+
It additionally exposes geospatial-specific TIFF tag metadata.
10+
11+
### Tests
12+
13+
Download the following file for use in the tests.
414

515
```
616
aws s3 cp s3://naip-visualization/ny/2022/60cm/rgb/40073/m_4007307_sw_18_060_20220803.tif ./ --request-payer

src/async_reader.rs

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
use std::io::{Cursor, SeekFrom};
2+
use std::ops::Range;
3+
use std::sync::Arc;
4+
5+
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
16
use bytes::Bytes;
27
use futures::future::{BoxFuture, FutureExt, TryFutureExt};
38
use object_store::ObjectStore;
4-
use std::io::SeekFrom;
5-
use std::ops::Range;
6-
use std::sync::Arc;
79

810
use crate::error::{AiocogeoError, Result};
911

@@ -111,3 +113,112 @@ impl AsyncFileReader for ObjectReader {
111113
.boxed()
112114
}
113115
}
116+
117+
#[derive(Debug, Clone, Copy, Default)]
118+
pub enum Endianness {
119+
#[default]
120+
LittleEndian,
121+
BigEndian,
122+
}
123+
124+
/// A wrapper around an [ObjectStore] that provides a seek-oriented interface
125+
// TODO: in the future add buffering to this
126+
pub(crate) struct AsyncCursor {
127+
reader: Box<dyn AsyncFileReader>,
128+
offset: usize,
129+
endianness: Endianness,
130+
}
131+
132+
/// Macro to generate functions to read scalar values from the cursor
133+
macro_rules! impl_read_byteorder {
134+
($method_name:ident, $typ:ty) => {
135+
pub(crate) async fn $method_name(&mut self) -> $typ {
136+
let mut buf = Cursor::new(self.read(<$typ>::BITS as usize / 8).await);
137+
match self.endianness {
138+
Endianness::LittleEndian => buf.$method_name::<LittleEndian>().unwrap(),
139+
Endianness::BigEndian => buf.$method_name::<BigEndian>().unwrap(),
140+
}
141+
}
142+
};
143+
}
144+
145+
impl AsyncCursor {
146+
pub(crate) fn new(reader: Box<dyn AsyncFileReader>) -> Self {
147+
Self {
148+
reader,
149+
offset: 0,
150+
endianness: Default::default(),
151+
}
152+
}
153+
154+
pub(crate) fn set_endianness(&mut self, endianness: Endianness) {
155+
self.endianness = endianness;
156+
}
157+
158+
pub(crate) fn into_inner(self) -> Box<dyn AsyncFileReader> {
159+
self.reader
160+
}
161+
162+
pub(crate) async fn read(&mut self, length: usize) -> Bytes {
163+
let range = self.offset..self.offset + length;
164+
self.offset += length;
165+
self.reader.get_bytes(range).await.unwrap()
166+
}
167+
168+
/// Read a u8 from the cursor
169+
pub(crate) async fn read_u8(&mut self) -> u8 {
170+
let buf = self.read(1).await;
171+
Cursor::new(buf).read_u8().unwrap()
172+
}
173+
174+
/// Read a i8 from the cursor
175+
pub(crate) async fn read_i8(&mut self) -> i8 {
176+
let buf = self.read(1).await;
177+
Cursor::new(buf).read_i8().unwrap()
178+
}
179+
180+
impl_read_byteorder!(read_u16, u16);
181+
impl_read_byteorder!(read_u32, u32);
182+
impl_read_byteorder!(read_u64, u64);
183+
impl_read_byteorder!(read_i16, i16);
184+
impl_read_byteorder!(read_i32, i32);
185+
impl_read_byteorder!(read_i64, i64);
186+
187+
pub(crate) async fn read_f32(&mut self) -> f32 {
188+
let mut buf = Cursor::new(self.read(4).await);
189+
match self.endianness {
190+
Endianness::LittleEndian => buf.read_f32::<LittleEndian>().unwrap(),
191+
Endianness::BigEndian => buf.read_f32::<BigEndian>().unwrap(),
192+
}
193+
}
194+
195+
pub(crate) async fn read_f64(&mut self) -> f64 {
196+
let mut buf = Cursor::new(self.read(8).await);
197+
match self.endianness {
198+
Endianness::LittleEndian => buf.read_f64::<LittleEndian>().unwrap(),
199+
Endianness::BigEndian => buf.read_f64::<BigEndian>().unwrap(),
200+
}
201+
}
202+
203+
#[allow(dead_code)]
204+
pub(crate) fn reader(&self) -> &dyn AsyncFileReader {
205+
&self.reader
206+
}
207+
208+
pub(crate) async fn get_range(&mut self, range: Range<usize>) -> Result<Bytes> {
209+
self.reader.get_bytes(range).await
210+
}
211+
212+
/// Advance cursor position by a set amount
213+
pub(crate) fn advance(&mut self, amount: usize) {
214+
self.offset += amount;
215+
}
216+
217+
pub(crate) fn seek(&mut self, offset: usize) {
218+
self.offset = offset;
219+
}
220+
221+
pub(crate) fn position(&self) -> usize {
222+
self.offset
223+
}
224+
}

src/cog.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bytes::Bytes;
22

3-
use crate::cursor::{Endianness, ObjectStoreCursor};
3+
use crate::async_reader::{AsyncCursor, Endianness};
44
use crate::error::Result;
55
use crate::ifd::ImageFileDirectories;
66
use crate::AsyncFileReader;
@@ -13,7 +13,7 @@ pub struct COGReader {
1313

1414
impl COGReader {
1515
pub async fn try_open(reader: Box<dyn AsyncFileReader>) -> Result<Self> {
16-
let mut cursor = ObjectStoreCursor::new(reader);
16+
let mut cursor = AsyncCursor::new(reader);
1717
let magic_bytes = cursor.read(2).await;
1818
// Should be b"II" for little endian or b"MM" for big endian
1919
if magic_bytes == Bytes::from_static(b"II") {

src/cursor.rs

Lines changed: 0 additions & 117 deletions
This file was deleted.

src/enums.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.
File renamed without changes.
File renamed without changes.

src/geo/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mod affine;
2+
mod geo_key_directory;
3+
mod partial_reads;
4+
5+
pub use affine::AffineTransform;
6+
pub use geo_key_directory::{GeoKeyDirectory, GeoKeyTag};
File renamed without changes.

0 commit comments

Comments
 (0)