From e0236380fca785fefd2b4406167dd5320a0cebe6 Mon Sep 17 00:00:00 2001 From: Elias Carvalho <73039601+eliascarv@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:25:38 -0300 Subject: [PATCH] Add `image` function (#14) * Permute the TIFF dimensions by default * Add 'image' function --- README.md | 13 +++++++++++++ src/image.jl | 18 +++++++++++++++--- src/save.jl | 5 ++++- test/data/natural_earth_1.tif | Bin 0 -> 39718 bytes test/runtests.jl | 23 +++++++++++++++++++++++ 5 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 test/data/natural_earth_1.tif diff --git a/README.md b/README.md index ac31ee0..7bee9a9 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,19 @@ julia> metadata = GeoTIFF.metadata(geotiff) GeoTIFF.Metadata(...) ``` +And use the `GeoTIFF.image` function to get the image with corrected axes: + +```julia +julia> GeoTIFF.image(geotiff) +100×100 PermutedDimsArray(::TiffImages.DenseTaggedImage{...}, (2, 1)) with eltype RGB{N0f16}: + RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) … RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) + RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) + RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) + ⋮ ⋱ + RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) + RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) RGB(1.0, 1.0, 1.0) +``` + GeoTIFF.jl defines several utilities to easily retrieve metadata information: ```julia diff --git a/src/image.jl b/src/image.jl index ff23b4c..28a32e9 100644 --- a/src/image.jl +++ b/src/image.jl @@ -7,8 +7,13 @@ Image type returned by the [`GeoTIFF.load`](@ref) function. -See the [`GeoTIFF.tiff`](@ref) and [`GeoTIFF.metadata`](@ref) functions -to get the TIFF image and metadata respectively. +See the [`GeoTIFF.metadata`](@ref) and [`GeoTIFF.image`](@ref) functions +to get the metadata and the image with corrected axes, respectively. + +### Notes + +* The [`GeoTIFF.image`](@ref) function is necessary because + the GeoTIFF format swaps the order of the image axes; """ struct GeoTIFFImage{T,N,I<:AbstractTIFF{T,N}} <: AbstractArray{T,N} tiff::I @@ -29,6 +34,13 @@ GeoTIFF metadata of the `geotiff` image. """ metadata(geotiff::GeoTIFFImage) = geotiff.metadata +""" + GeoTIFF.image(geotiff) + +Image of the `geotiff` with corrected axis. +""" +image(geotiff::GeoTIFFImage) = PermutedDimsArray(geotiff.tiff, (2, 1)) + """ GeoTIFF.nchannels(geotiff) @@ -41,7 +53,7 @@ nchannels(geotiff::GeoTIFFImage) = nchannels(geotiff.tiff) `i`'th channel of the `geotiff` image. """ -channel(geotiff::GeoTIFFImage, i) = mappedarray(c -> channel(c, i), geotiff.tiff) +channel(geotiff::GeoTIFFImage, i) = mappedarray(c -> channel(c, i), image(geotiff)) # AbstractArray interface Base.size(geotiff::GeoTIFFImage) = size(geotiff.tiff) diff --git a/src/save.jl b/src/save.jl index fcb2aaa..94e0a77 100644 --- a/src/save.jl +++ b/src/save.jl @@ -28,7 +28,10 @@ end Save in the file `fname` an image (array of colors) `img` with passed GeoTIFF `metadata`. """ -save(fname, img::AbstractArray{<:WidePixelOrColorant}; kwargs...) = save(fname, DenseTaggedImage(img); kwargs...) +function save(fname, img::AbstractArray{<:WidePixelOrColorant}; kwargs...) + tiff = DenseTaggedImage(PermutedDimsArray(img, (2, 1))) + save(fname, tiff; kwargs...) +end """ GeoTIFF.save(fname, channels...; metadata=GeoTIFF.Metadata()) diff --git a/test/data/natural_earth_1.tif b/test/data/natural_earth_1.tif new file mode 100644 index 0000000000000000000000000000000000000000..29fdb3adfa634eb4dacf40ab8c0b4ef2dd20e1e1 GIT binary patch literal 39718 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