- can now save the common types

This commit is contained in:
Wim Pomp
2024-10-09 12:05:11 +02:00
parent 82931f7715
commit 52785037b9
6 changed files with 241 additions and 659 deletions

596
Cargo.lock generated
View File

@@ -1,596 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anyhow"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cc"
version = "1.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "fraction"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7"
dependencies = [
"lazy_static",
"num",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "iana-time-zone"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "indoc"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "matrixmultiply"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
dependencies = [
"autocfg",
"rawpointer",
]
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "ndarray"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
dependencies = [
"matrixmultiply",
"num-complex",
"num-integer",
"num-traits",
"portable-atomic",
"portable-atomic-util",
"rawpointer",
]
[[package]]
name = "num"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "portable-atomic-util"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcdd8420072e66d54a407b3316991fe946ce3ab1083a7f575b2463866624704d"
dependencies = [
"portable-atomic",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pyo3"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225"
dependencies = [
"anyhow",
"cfg-if",
"indoc",
"libc",
"memoffset",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3"
dependencies = [
"once_cell",
"python3-dll-a",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1"
dependencies = [
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn",
]
[[package]]
name = "python3-dll-a"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0b78171a90d808b319acfad166c4790d9e9759bbc14ac8273fe133673dd41b"
dependencies = [
"cc",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rawpointer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-lexicon"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tiffwrite"
version = "2024.10.0"
dependencies = [
"anyhow",
"chrono",
"fraction",
"ndarray",
"num",
"pyo3",
"rayon",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unindent"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@@ -1,21 +1,23 @@
[package] [package]
name = "tiffwrite" name = "tiffwrite"
version = "2024.10.0" version = "2024.10.1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib] [lib]
name = "tiffwrite" name = "tiffwrite"
crate-type = ["cdylib"] crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
pyo3 = { version = "0.22.3", features = ["extension-module", "abi3-py310", "generate-import-lib", "anyhow"] } pyo3 = { version = "0.21.2", features = ["extension-module", "abi3-py310", "generate-import-lib", "anyhow", "multiple-pymethods"] }
anyhow = "1.0.89" anyhow = "1.0.89"
rayon = "1.10.0" rayon = "1.10.0"
fraction = "0.15.3" fraction = "0.15.3"
num = "0.4.3" num = "0.4.3"
ndarray = "0.16.1" ndarray = "0.15.6"
chrono = "0.4.38" chrono = "0.4.38"
numpy = "0.21.0"
futures = "0.3.31"
[features] [features]
nopython = [] nopython = []

View File

@@ -1,3 +1,6 @@
#[cfg(not(feature = "nopython"))]
mod py;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
@@ -15,6 +18,7 @@ use chrono::Utc;
const TAG_SIZE: usize = 20; const TAG_SIZE: usize = 20;
const OFFSET_SIZE: usize = 8; const OFFSET_SIZE: usize = 8;
const OFFSET: u64 = 16; const OFFSET: u64 = 16;
const COMPRESSION: u16 = 1;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -238,7 +242,7 @@ struct Frame {
image_width: u32, image_width: u32,
image_length: u32, image_length: u32,
bits_per_sample: u16, bits_per_sample: u16,
compression: u16, sample_format: u16,
tile_width: u16, tile_width: u16,
tile_length: u16, tile_length: u16,
extra_tags: Vec<Tag> extra_tags: Vec<Tag>
@@ -246,17 +250,63 @@ struct Frame {
impl Frame { impl Frame {
fn new( fn new(
tilebyteoffsets: Vec<u64>, tilebytecounts: Vec<u64>, image_width: u32, tilebyteoffsets: Vec<u64>, tilebytecounts: Vec<u64>, image_width: u32, image_length: u32,
image_length: u32, bits_per_sample: u16, compression: u16, tile_width: u16, tile_length: u16 bits_per_sample: u16, sample_format: u16, tile_width: u16, tile_length: u16
) -> Self { ) -> Self {
Frame { Frame {
tilebyteoffsets, tilebytecounts, image_width, image_length, bits_per_sample, tilebyteoffsets, tilebytecounts, image_width, image_length, bits_per_sample,
compression, tile_width, tile_length, extra_tags: Vec::new() sample_format, tile_width, tile_length, extra_tags: Vec::new()
} }
} }
} }
pub trait Bytes {
const BITS_PER_SAMPLE: u16;
const SAMPLE_FORMAT: u16;
fn bytes(&self) -> Vec<u8>;
}
macro_rules! bytes_impl {
($T:ty, $bits_per_sample:expr, $sample_format:expr) => {
impl Bytes for $T {
const BITS_PER_SAMPLE: u16 = $bits_per_sample;
const SAMPLE_FORMAT: u16 = $sample_format;
#[inline]
fn bytes(&self) -> Vec<u8>
{
self.to_le_bytes().to_vec()
}
}
};
}
bytes_impl!(u8, 8, 1);
bytes_impl!(u16, 16, 1);
bytes_impl!(u32, 32, 1);
bytes_impl!(u64, 64, 1);
bytes_impl!(u128, 128, 1);
#[cfg(target_pointer_width = "64")]
bytes_impl!(usize, 64, 1);
#[cfg(target_pointer_width = "32")]
bytes_impl!(usize, 32, 1);
bytes_impl!(i8, 8, 2);
bytes_impl!(i16, 16, 2);
bytes_impl!(i32, 32, 2);
bytes_impl!(i64, 64, 2);
bytes_impl!(i128, 128, 2);
#[cfg(target_pointer_width = "64")]
bytes_impl!(isize, 64, 2);
#[cfg(target_pointer_width = "32")]
bytes_impl!(isize, 32, 2);
bytes_impl!(f32, 32, 3);
bytes_impl!(f64, 64, 3);
#[derive(Debug)] #[derive(Debug)]
pub struct IJTiffFile { pub struct IJTiffFile {
file: File, file: File,
@@ -331,19 +381,6 @@ impl IJTiffFile {
desc desc
} }
pub fn save(&mut self, frame: Array2<u16>, c: usize, z: usize, t: usize,
extra_tags: Option<Vec<Tag>>) -> Result<()> {
let mut compressed_frame = self.compress_frame(frame)?;
if let Some(tags) = extra_tags {
for tag in tags {
compressed_frame.extra_tags.push(tag);
}
}
self.frames.insert(self.get_frame_number(c, z, t), compressed_frame);
Ok(())
}
fn get_frame_number(&self, c: usize, z: usize, t: usize) -> (usize, u8) { fn get_frame_number(&self, c: usize, z: usize, t: usize) -> (usize, u8) {
if let (None, None) = (self.colormap.as_ref(), self.colors.as_ref()) { if let (None, None) = (self.colormap.as_ref(), self.colors.as_ref()) {
(z + t * self.shape.1, c as u8) (z + t * self.shape.1, c as u8)
@@ -352,7 +389,7 @@ impl IJTiffFile {
} }
} }
pub fn hash<T: Hash>(value: &T) -> u64 { fn hash<T: Hash>(value: &T) -> u64 {
let mut hasher = DefaultHasher::new(); let mut hasher = DefaultHasher::new();
value.hash(&mut hasher); value.hash(&mut hasher);
hasher.finish() hasher.finish()
@@ -383,21 +420,32 @@ impl IJTiffFile {
} }
} }
fn compress_frame(&mut self, frame: Array2<u16>) -> Result<Frame> { pub fn save<T: Bytes + Clone + Zero>(&mut self, frame: Array2<T>, c: usize, z: usize, t: usize,
extra_tags: Option<Vec<Tag>>) -> Result<()> {
self.compress_frame(frame, c, z, t, extra_tags);
Ok(())
}
fn compress_frame<T: Bytes + Clone + Zero>(&mut self, frame: Array2<T>, c: usize, z: usize, t: usize,
extra_tags: Option<Vec<Tag>>) {
let image_width = frame.shape()[0] as u32; let image_width = frame.shape()[0] as u32;
let image_length = frame.shape()[1] as u32; let image_length = frame.shape()[1] as u32;
let mut tilebyteoffsets = Vec::new(); let mut tilebyteoffsets = Vec::new();
let mut tilebytecounts = Vec::new(); let mut tilebytecounts = Vec::new();
let tiles = IJTiffFile::tile(frame.reversed_axes(), 64); let tiles = IJTiffFile::tile(frame.reversed_axes(), 64);
for tile in tiles { for tile in tiles {
let bytes: Vec<u8> = tile.into_flat().into_iter().map( let bytes: Vec<u8> = tile.map(|x| x.bytes()).into_iter().flatten().collect();
|x| x.to_le_bytes()).into_iter().flatten().collect();
tilebytecounts.push(bytes.len() as u64); tilebytecounts.push(bytes.len() as u64);
tilebyteoffsets.push(self.write(&bytes)?); tilebyteoffsets.push(self.write(&bytes).unwrap());
} }
let mut frame = Frame::new(tilebyteoffsets, tilebytecounts, image_width, image_length,
Ok(Frame::new(tilebyteoffsets, tilebytecounts, image_width, image_length, T::BITS_PER_SAMPLE, T::SAMPLE_FORMAT, 64, 64);
16, 1, 64, 64)) if let Some(tags) = extra_tags {
for tag in tags {
frame.extra_tags.push(tag);
}
}
self.frames.insert(self.get_frame_number(c, z, t), frame);
} }
fn tile<T: Clone + Zero>(frame: Array2<T>, size: usize) -> Vec<Array2<T>> { fn tile<T: Clone + Zero>(frame: Array2<T>, size: usize) -> Vec<Array2<T>> {
@@ -438,15 +486,13 @@ impl IJTiffFile {
fn get_colormap(&self, colormap: &Vec<u16>) -> Result<Vec<u16>> { fn get_colormap(&self, colormap: &Vec<u16>) -> Result<Vec<u16>> {
todo!(); todo!();
Ok(Vec::new())
} }
fn get_color(&self, colors: (u8, u8, u8)) -> Result<Vec<u16>> { fn get_color(&self, colors: (u8, u8, u8)) -> Result<Vec<u16>> {
todo!(); todo!();
Ok(Vec::new())
} }
pub fn close(&mut self) -> Result<()> { fn close(&mut self) -> Result<()> {
let mut where_to_write_next_ifd_offset = OFFSET - OFFSET_SIZE as u64; let mut where_to_write_next_ifd_offset = OFFSET - OFFSET_SIZE as u64;
let mut warn = false; let mut warn = false;
for frame_number in 0..self.n_frames { for frame_number in 0..self.n_frames {
@@ -467,7 +513,7 @@ impl IJTiffFile {
ifd.push_tag(Tag::long(256, vec![frame.image_width])); ifd.push_tag(Tag::long(256, vec![frame.image_width]));
ifd.push_tag(Tag::long(257, vec![frame.image_length])); ifd.push_tag(Tag::long(257, vec![frame.image_length]));
ifd.push_tag(Tag::short(258, vec![frame.bits_per_sample; frame_count])); ifd.push_tag(Tag::short(258, vec![frame.bits_per_sample; frame_count]));
ifd.push_tag(Tag::short(259, vec![1])); ifd.push_tag(Tag::short(259, vec![COMPRESSION]));
ifd.push_tag(Tag::ascii(270, &self.description())); ifd.push_tag(Tag::ascii(270, &self.description()));
ifd.push_tag(Tag::short(277, vec![frame_count as u16])); ifd.push_tag(Tag::short(277, vec![frame_count as u16]));
ifd.push_tag(Tag::ascii(305, "tiffwrite_rs")); ifd.push_tag(Tag::ascii(305, "tiffwrite_rs"));
@@ -475,6 +521,7 @@ impl IJTiffFile {
ifd.push_tag(Tag::short(323, vec![frame.tile_length])); ifd.push_tag(Tag::short(323, vec![frame.tile_length]));
ifd.push_tag(Tag::long8(324, tilebyteoffsets)); ifd.push_tag(Tag::long8(324, tilebyteoffsets));
ifd.push_tag(Tag::long8(325, tilebytecounts)); ifd.push_tag(Tag::long8(325, tilebytecounts));
ifd.push_tag(Tag::short(339, vec![frame.sample_format]));
if frame_number == 0 { if frame_number == 0 {
if let Some(colormap) = &self.colormap { if let Some(colormap) = &self.colormap {
ifd.push_tag(Tag::short(320, self.get_colormap(colormap)?)); ifd.push_tag(Tag::short(320, self.get_colormap(colormap)?));

View File

@@ -1,28 +1,23 @@
#[cfg(not(feature = "nopython"))]
mod py;
mod lib;
use anyhow::Result; use anyhow::Result;
use ndarray::{s, Array2}; use ndarray::{s, Array2};
use rayon::prelude::*; use tiffwrite::IJTiffFile;
use crate::lib::IJTiffFile;
fn main() -> Result<()> { fn main() -> Result<()> {
println!("Hello World!"); println!("Hello World!");
let mut f = IJTiffFile::new("foo.tif", (1, 2, 1))?; let mut f = IJTiffFile::new("foo.tif", (2, 1, 1))?;
let mut arr = Array2::<u16>::zeros((100, 100)); let mut arr = Array2::<u16>::zeros((100, 100));
// for i in 0..arr.shape()[0] { for i in 0..arr.shape()[0] {
// for j in 0..arr.shape()[1] { for j in 0..arr.shape()[1] {
// arr[[i, j]] = i as u16; arr[[i, j]] = i as u16;
// } }
// } }
f.save(arr.to_owned(), 0, 0, 0, None)?; f.save(arr.to_owned(), 0, 0, 0, None)?;
// let mut arr = Array2::<u16>::zeros((100, 100)); let mut arr = Array2::<u16>::zeros((100, 100));
// arr.slice_mut(s![64.., ..64]).fill(1); arr.slice_mut(s![64.., ..64]).fill(1);
// arr.slice_mut(s![..64, 64..]).fill(2); arr.slice_mut(s![..64, 64..]).fill(2);
// arr.slice_mut(s![64.., 64..]).fill(3); arr.slice_mut(s![64.., 64..]).fill(3);
f.save(arr.to_owned(), 0, 1,0, None)?; f.save(arr.to_owned(), 1, 0,0, None)?;
Ok(()) Ok(())
} }

View File

@@ -1,9 +1,8 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::lib::{IJTiffFile, Tag}; use crate::{IJTiffFile, Tag};
use std::time::Duration;
use pyo3::types::{PyInt, PyString};
use fraction::Fraction; use fraction::Fraction;
use num::Complex; use num::Complex;
use numpy::{PyReadonlyArray2, PyArrayMethods};
#[pyclass(subclass)] #[pyclass(subclass)]
@@ -106,14 +105,14 @@ impl PyTag {
#[pyo3(name = "IJTiffFile")] #[pyo3(name = "IJTiffFile")]
#[derive(Debug)] #[derive(Debug)]
struct PyIJTiffFile { struct PyIJTiffFile {
ijtifffile: IJTiffFile ijtifffile: Option<IJTiffFile>
} }
#[pymethods] #[pymethods]
impl PyIJTiffFile { impl PyIJTiffFile {
#[new] #[new]
fn new(path: &str, shape: (usize, usize, usize), dtype: &str) -> PyResult<Self> { fn new(path: &str, shape: (usize, usize, usize)) -> PyResult<Self> {
Ok(PyIJTiffFile { ijtifffile: IJTiffFile::new(path, shape)? } ) Ok(PyIJTiffFile { ijtifffile: Some(IJTiffFile::new(path, shape)?) } )
} }
fn with_colors(&mut self, colors: (u8, u8, u8)) -> Self { fn with_colors(&mut self, colors: (u8, u8, u8)) -> Self {
@@ -140,19 +139,67 @@ impl PyIJTiffFile {
todo!() todo!()
} }
fn append_extra_tag(&mut self, extra_tag: PyTag) { fn append_extra_tag(&mut self, tag: PyTag) {
if let Some(extra_tags) = self.ijtifffile.extra_tags.as_mut() { if let Some(ijtifffile) = self.ijtifffile.as_mut() {
extra_tags.push(extra_tag.tag); if let Some(extra_tags) = ijtifffile.extra_tags.as_mut() {
extra_tags.push(tag.tag);
} else { } else {
self.ijtifffile.extra_tags = Some(vec![extra_tag.tag]); ijtifffile.extra_tags = Some(vec![tag.tag]);
}
} }
} }
fn extend_extra_tags(&mut self, tags: Vec<PyTag>) {
if let Some(ijtifffile) = self.ijtifffile.as_mut() {
if let Some(extra_tags) = ijtifffile.extra_tags.as_mut() {
extra_tags.extend(tags.into_iter().map(|x| x.tag));
} else {
ijtifffile.extra_tags = Some(tags.into_iter().map(|x| x.tag).collect());
}
}
}
fn close(&mut self) -> PyResult<()> {
self.ijtifffile.take();
Ok(())
}
} }
macro_rules! impl_save {
($T:ty, $t:ident) => {
#[pymethods]
impl PyIJTiffFile {
fn $t(&mut self, frame: PyReadonlyArray2<$T>, c: usize, t: usize, z: usize,
extra_tags: Option<Vec<PyTag>>) -> PyResult<()> {
let extra_tags = if let Some(extra_tags) = extra_tags {
Some(extra_tags.into_iter().map(|x| x.tag).collect())
} else {
None
};
if let Some(ijtifffile) = self.ijtifffile.as_mut() {
ijtifffile.save(frame.to_owned_array(), c, t, z, extra_tags)?;
}
Ok(())
}
}
};
}
impl_save!(u8, save_u8);
impl_save!(u16, save_u16);
impl_save!(u32, save_u32);
impl_save!(u64, save_u64);
impl_save!(i8, save_i8);
impl_save!(i16, save_i16);
impl_save!(i32, save_i32);
impl_save!(i64, save_i64);
impl_save!(f32, save_f32);
impl_save!(f64, save_f64);
#[pymodule] #[pymodule]
fn tiffwrite(m: &Bound<'_, PyModule>) -> PyResult<()> { fn tiffwrite(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyTag>()?;
m.add_class::<PyIJTiffFile>()?; m.add_class::<PyIJTiffFile>()?;
Ok(()) Ok(())
} }

View File

@@ -1,5 +1,92 @@
from __future__ import annotations
import numpy as np
from typing import Any, Self, Sequence
from pathlib import Path
from numpy.typing import ArrayLike, DTypeLike
from . import tiffwrite as rs from . import tiffwrite as rs
class IJTiffFile(rs.IJTiffFile): __all__ = ['Tag', 'IJTiffFile', 'tiffwrite']
class IFD(dict):
pass pass
class Tag(rs.Tag):
pass
class IJTiffFile(rs.IJTiffFile):
def __new__(cls, path: str | Path, shape: tuple[int, int, int], dtype: DTypeLike = 'uint16',
colors: Sequence[str] = None, colormap: str = None, pxsize: float = None,
deltaz: float = None, timeinterval: float = None, comment: str = None,
**extratags: Tag.Value | Tag) -> None:
new = super().__new__(cls, str(path), shape)
if colors is not None:
new = new.with_colors(colors)
if colormap is not None:
new = new.with_colormap(colormap)
if pxsize is not None:
new = new.with_pxsize(pxsize)
if deltaz is not None:
new = new.with_deltaz(deltaz)
if timeinterval is not None:
new = new.with_timeinterval(timeinterval)
if comment is not None:
new = new.with_comment(comment)
if extratags:
new = new.extend_extratags(extratags)
return new
def __init__(self, path: str | Path, shape: tuple[int, int, int], dtype: DTypeLike = 'uint16',
colors: Sequence[str] = None, colormap: str = None, pxsize: float = None,
deltaz: float = None, timeinterval: float = None, comment: str = None,
**extratags: Tag.Value | Tag) -> None:
self.path = Path(path)
self.dtype = np.dtype(dtype)
def __enter__(self) -> Self:
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
def save(self, frame: ArrayLike, c: int, z: int, t: int) -> None:
frame = np.asarray(frame).astype(self.dtype)
match self.dtype:
case np.uint8:
self.save_u8(frame, c, z, t)
case np.uint16:
self.save_u16(frame, c, z, t)
case np.uint32:
self.save_u32(frame, c, z, t)
case np.uint64:
self.save_u64(frame, c, z, t)
case np.int8:
self.save_i8(frame, c, z, t)
case np.int16:
self.save_i16(frame, c, z, t)
case np.int32:
self.save_i32(frame, c, z, t)
case np.int64:
self.save_i64(frame, c, z, t)
case np.float32:
self.save_f32(frame, c, z, t)
case np.float64:
self.save_f64(frame, c, z, t)
case _:
raise TypeError(f'Cannot save type {self.dtype}')
def tiffwrite(file: str | Path, data: ArrayLike, axes: str = 'TZCXY', dtype: DTypeLike = None, bar: bool = False,
*args: Any, **kwargs: Any) -> None:
""" file: string; filename of the new tiff file
data: 2 to 5D numpy array
axes: string; order of dimensions in data, default: TZCXY for 5D, ZCXY for 4D, CXY for 3D, XY for 2D data
dtype: string; datatype to use when saving to tiff
bar: bool; whether to show a progress bar
other args: see IJTiffFile
"""